March 7, 2020

Codeforces Round #626 div.2 题解

凸包周长 / 直径多长 / 一进考场 / 全都忘光

Codeforces Round #626 div.2 题解

A. Even Subset Sum Problem

题意

给你n个数,问你能否选择其中的若干个数使他们的和为偶数,如果不能输出-1,如果能输出一个可行的选数方案

思路

显然不能的情况只有一种就是n==1且这个数是奇数
剩下的情况就是随便找两个奇数或者找一个偶数的位置输出就好了

代码

#include<iostream>
#include<cstdio>
using namespace std;
const int maxn=100+10;
int a[maxn];
int main(){
	int T;
	scanf("%d",&T);
	while(T--){
		int n;
		cin>>n;
		int flag=0;
		for(int i=1;i<=n;i++){
			cin>>a[i];
		}
		if(n==1&&a[1]%2!=0){
			cout<<"-1"<<endl;	
		}
		else{
			int fl=0;
			for(int i=1;i<=n;i++){
				if(a[i]%2==0){
					cout<<"1"<<endl<<i<<endl;
					fl=1;
					break;
				}
			}
			if(!fl){
				cout<<"2"<<endl<<"1 2"<<endl;	
			} 
		}
	}
}

B. Count Subrectangles

题意

这题读了半天才读懂... 意思是给你两个只由1和0构成的序列 An 和 Bn ,可以构造出一个矩阵Cnn
其中Cij=Ai x Bj,然后给你一个k,问这个矩阵中面积为k且只由1构成的子矩阵有几个。
11111

思路

每个子矩阵都是由A序列中的某个区间和B序列中的某个区间构成的,如果子矩阵全为1的话则A、B序列中对应的两个区间也都全为1,所以就把两个序列合并处理(例如:1 1 0 1 0 1转化为 2 1 1),然后再枚举k的因子,k=xy ,然后在合并后的序列中分别找大于x/y的部分然后相乘再求和就好了,注意要开long long!

代码

#include<cstdio>
#include<iostream>
using namespace std;
const int maxn=40000+10;
int a[maxn],b[maxn];
int aaa[maxn],bbb[maxn];
int main(){
	int n,m,k;
	cin>>n>>m>>k;
	int acnt=1,now=0;
	for(int i=1;i<=n;i++){
		cin>>a[i];
		if(a[i]) now++;
		else{
			aaa[acnt]=now;
			now=0;acnt++;
		}
	}
	if(now!=0){
		aaa[acnt]=now;	
	}
	int bcnt=1;now=0;
	for(int i=1;i<=m;i++){
		cin>>b[i];
		if(b[i]) now++;
		else{
			bbb[bcnt]=now;
			now=0;bcnt++;	
		}
	}
	if(now!=0){
		bbb[bcnt]=now;	
	}
	long long ans=0;
	for(int i=1;i*i<=k;i++){
		if(k%i==0){
			long long ls1=0,ls2=0;
			for(int j=1;j<=acnt;j++){
				if(aaa[j]<i)continue;
				ls1+=aaa[j]-i+1;
			}
			int pp=k/i;
			for(int j=1;j<=bcnt;j++){
				if(bbb[j]<pp)continue;
				ls2+=bbb[j]-pp+1;
			}
			ans+=ls1*ls2;
			if(pp!=i){
				long long ls3=0,ls4=0;
				for(int j=1;j<=acnt;j++){
					if(aaa[j]<pp)continue;
					ls3+=aaa[j]-pp+1;
				}
				for(int j=1;j<=bcnt;j++){
					if(bbb[j]<i)continue;
					ls4+=bbb[j]-i+1;
				}
				ans+=ls3*ls4;
			}
		}	
	}
	cout<<ans;
	return 0;
}

C. Unusual Competitions

题意

给一串括号序列,每次移动任意调整子串中括号的顺序最少,每次移动花费的代价是子串的长度,问最少代价是多少。

思路

从左往右扫,显然只有前括号和后括号数量相等的时候,才能进行一次结算
结算的时候用栈来判断当前这一段能不能匹配的上,不能匹配就全交换,然后继续往后扫
最后如果括号有剩余说明不能匹配输出-1

代码

#include<cstdio>
#include<iostream>
#include<stack>
using namespace std;
const int maxn=1000000+10;
char a[maxn];
stack<int> s;
int main(){
	int n;
	cin>>n>>a+1;
	int now1=0,now2=0,a1=1,a2=2;
	int ans=0,st=1;
	for(int i=1;i<=n;i++){
		if(a[i]=='('){
			now1++;
		}
		else {
			now2++;
			if(now1==now2){
				for(int j=st;j<=i;j++){
					if(a[j]=='('){
						s.push(a1);	
					}
					else{
						if(s.top()==1){
							s.pop();
						}
						else{
							s.push(a2);	
						}
					}
				}
				if(!s.empty()){
					ans+=i-st+1;
				}
				st=i+1;now1=0;now2=0;
				while(!s.empty()){
					s.pop();
				}
			}
		}
		if(now1==now2&&now1!=0){
			ans+=i-st+1;
			st=i+1;now1=0;now2=0;
		}
	}
	if(now1!=0||now2!=0){
		cout<<"-1"<<endl;	
	}
	else cout<<ans<<endl;
}