zoukankan      html  css  js  c++  java
  • 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
    ",r-l+1);
    		for(int i=l;i<=r;i++){
    			printf("%d%c",i,(i==r)?'
    ':' ');
    		}
    	}
    	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
    ",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
    ",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
    ",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
    ",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;
    }
    
  • 相关阅读:
    个人作业——软件工程实践总结作业
    团队作业第二次—项目选题报告
    结对第二次—文献摘要热词统计及进阶需求
    结对第一次—原型设计(文献摘要热词统计)
    第一次作业-准备篇
    Java面向对象课程设计——购物车
    第04次作业-树
    第03次作业-栈和队列
    第02次作业-线性表
    01——绪论作业
  • 原文地址:https://www.cnblogs.com/fried-chicken/p/12468359.html
Copyright © 2011-2022 走看看