Codeforces Round #626 (Div. 2, based on Moscow Open Olympiad in Informatics)部分(A~E)题解

(A) Even Subset Sum Problem

题解:因为n非常非常小,直接暴力枚举所有区间即可。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
typedef double db;
int t,l,r,n,a[110],s[110];
int main(){
	cin>>t;
	while(t--){
		cin>>n;
		for(int i=1;i<=n;i++)	cin>>a[i];
		for(int i=1;i<=n;i++)	s[i]=s[i-1]+a[i];
		l=r=-1;
		for(int i=1;i<=n;i++){
			int flag=0;
			for(int j=i;j<=n;j++){
				if((s[j]-s[i-1])%2==0){
					l=i;r=j;flag=1;
					break;		
				}
			}
			if(flag)	break;
		}
		if(l==-1){
			puts("-1");
			continue;
		}
		printf("%d\n",r-l+1);
		for(int i=l;i<=r;i++){
			printf("%d%c",i,(i==r)?'\n':' ');
		}
	}
	return 0;
}

(B) Count Subrectangles

题解:由于对于大小为\(k\)的子矩形来说,其较短边是其较小的因子,所以其取值有\(\sqrt{k}\)种,我们只要枚举这些较短边长,然后问题就变成了:找到输入中有多少种方法可以选择一段连续的1,使得1的长度与我们需求的边长相等,模拟即可。注意爆int,以及枚举时分别要枚举较短边在行和较短边在列两种情况,特别的,因子恰为\(\sqrt{k}\)时,注意不要计算两遍。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
typedef double db;
int n,m,k,a[40010],b[40010];
int ap[40010],bp[40010];
int fac[40010],p;
int main(){
	cin>>n>>m>>k;
	for(int i=1;i<=n;i++)	cin>>a[i];
	for(int i=1;i<=n;i++)	ap[i]=((a[i]==0)?0:ap[i-1]+1);
	for(int i=1;i<=m;i++)	cin>>b[i];
	for(int i=1;i<=m;i++)	bp[i]=((b[i]==0)?0:bp[i-1]+1);
	for(int i=1;i*i<=k;i++){
		if(k%i==0){
			fac[++p]=i;
		}
	}
	ll ans=0;
	for(int i=1;i<=p;i++){
		ll tot=0,t1,t2;
		t1=t2=0;
		for(int j=1;j<=n;j++){
			if(ap[j]>=fac[i]){
				t1++;
			}
		}
		for(int j=1;j<=m;j++){
			if(bp[j]>=k/fac[i]){
				t2++;
			}
		}
		tot+=t1*t2;
		t1=t2=0;
		for(int j=1;j<=n;j++){
			if(ap[j]>=k/fac[i]){
				t1++;
			}
		}
		for(int j=1;j<=m;j++){
			if(bp[j]>=fac[i]){
				t2++;
			}
		}
		tot+=t1*t2;
		if(fac[i]==k/fac[i])	tot/=2ll;
		ans=ans+tot;
	}
	printf("%lld\n",ans);
	return 0;
}

(C) Unusual Competitions

题解:一个很直接的想法就是用栈来瞎搞,但也不能太瞎搞,比如 )((()))( 这样的例子,答案就是8,所以不能只用一个简单的栈,中间互相匹配掉的串长也要有所记录。
注意到这一点后,模拟即可。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
typedef double db;
stack<int> st;
int n,r,l;
char s[1000010];
int main(){
	scanf("%d%s",&n,s+1);
	int ans=0,len=0;
	for(int i=1;i<=n;i++){
		len++;
		if(s[i]=='('){
			r++;
		}
		else{
			if(r)	r--;
			else	l++;
		}
		if(l==r){
			if(r)	ans+=len;
			l=r=len=0;
		}
	}
	if(l||r){
		puts("-1");
	}
	else{
		printf("%d\n",ans);
	}
	return 0;
}

(D) Present

题解:本题的思路是经典的按位考虑贡献,考虑第\(i\)位(最低位记为0),将所有数对\(2^{i+1}\)取模获得后i位数字,那么只有两种情况,会对\(i\)位贡献一个“1”,即数组中某两数之和:
1、属于\([2^{i},2^{i+1}-1]\)
2、属于\([2^{i+1}+2^{i},2^{i+2}-1]\)

所以只要统计这样的两个数有多少对即可,可以用双指针、二分、树状数组(因为本题值域不大不小,恰好\(10^{7}\))。之中果然还是二分最好写呐,但cf排名靠前的很多中国大佬写的都是树状数组,不愧是数据结构大国(?

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
typedef double db;
int n,a[400010],b[400010];
int cnt[30];
int query(int lb,int rb){
	ll tmp=0;
	for(int i=1;i<=n;i++){
		ll pos1=lower_bound(b+1,b+1+n,lb-b[i])-b;
		ll pos2=upper_bound(b+1,b+1+n,rb-b[i])-b;
		tmp+=(pos2-pos1);
		if(2*b[i]<=rb&&2*b[i]>=lb)	tmp--;
	}
	assert(tmp%2==0);
	tmp/=2;
	return tmp%2;
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
	}
	int ans=0;
	for(int i=0;i<=24;i++){
		int k=(1<<(i+1)),tmp=0;
		for(int j=1;j<=n;j++){
			b[j]=a[j]%k;
		}
		sort(b+1,b+1+n);
		tmp+=query((1<<i),(1<<(i+1))-1);
		tmp+=query((1<<(i+1))+(1<<i),(1<<(i+2))-2);
		tmp%=2;
		ans=ans+(1<<i)*tmp;
	}
	printf("%d\n",ans);
	return 0;
}

(E) Instant Noodles

题解:其实这题并不太需要题解,干脆直接给个例子吧:
3 4
31 29 41
1 1
3 1
1 2
3 3
答案是1
如果把原题的三个样例叫一二三,这个是样例四的话,那么现在,可以观察一下,为什么样例一和三的结果非1,而样例2和4的结果是1;

如果你发现了的话,就快去AC吧;
如果你没有发现的话,规律是这样的:
如果有两个右部的点,他们相邻的左部点集完全相同,则他们算作“一类”;把每一类的数字加起来,求得到所有结果的\(gcd\),就是答案;

那么,咋判断两个集合是否相等呢?每个集合排序之后取模数哈希成一个ull,然后用map<ull,int>来维护是可以的。
这里突发奇想对set搞了个map维护,本来以为会超时,结果并没有?但这玩意儿看上去复杂度真的很危啊(

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
typedef double db;
map<set<int>,int> mp;
set<int> s[500005];
ll a[500005],p;
ll t,n,m,c[500005],u,v;
int main(){
	scanf("%lld",&t);
	while(t--){
		scanf("%lld%lld",&n,&m);
		for(int i=1;i<=n;i++){
			scanf("%lld",&c[i]);
		}
		for(int i=1;i<=m;i++){
			scanf("%lld%lld",&u,&v);
			s[v].insert(u);
		}
		for(int i=1;i<=n;i++){
			if(s[i].size()==0){
				continue;
			}
			if(mp.find(s[i])==mp.end()){
				mp[s[i]]=++p;
			}
			a[mp[s[i]]]+=c[i];
		}
		ll ans=a[1];
		for(int i=1;i<=p;i++){
			ans=__gcd(a[i],ans);
		}
		printf("%lld\n",ans);
		
		for(int i=1;i<=n;i++){
			s[i].clear();
		}
		mp.clear();
		for(int i=1;i<=p;i++){
			a[i]=0;
		}
		p=0;
	}
	return 0;
}
posted @ 2020-03-12 12:26  炸鸡块君  阅读(...)  评论(...编辑  收藏