• CF1559D 题解


    https://codeforces.com/contest/1559

    CF1559A

    把题目中的操作范围缩小一下,可以变成相邻两个按位与一下。我们不断地操作,必然能把所有数都变成所有数地按位与。

    #include<bits/stdc++.h>
    #define int long long
    #define rep(i,a,b) for(int i=(a);i<=(b);i++)
    #define per(i,a,b) for(int i=(a);i>=(b);i--)
    using namespace std;
    const int N=109;
    
    inline long long read() {
    	long long res=0, w=1; char c=getchar();
    	while(!isdigit(c)) {if(c=='-') w=-1; c=getchar();}
    	while(isdigit(c)) {res=res*10+c-48; c=getchar();}
    	return res*w;
    }
    
    int T,n,a[N];
    
    signed main() {
    	T=read();
    	while(T--) {
    		n=read(); int ans=(1ll<<30)-1;
    		rep(i,1,n) a[i]=read(), ans&=a[i];
    		printf("%lld
    ",ans);
    	}
    	return 0;
    }
    

    CF1559B

    考虑对于一段连续地问号区间:如果在一开始,那么就从后往前贪心;如果在最后面,就从前往后贪心;否则从两边贪心即可(其实现在想了想没这个必要,从一端贪心应该也是对的)。

    #include<bits/stdc++.h>
    #define int long long
    #define rep(i,a,b) for(int i=(a);i<=(b);i++)
    #define per(i,a,b) for(int i=(a);i>=(b);i--)
    using namespace std;
    const int N=109;
    
    inline long long read() {
    	long long res=0, w=1; char c=getchar();
    	while(!isdigit(c)) {if(c=='-') w=-1; c=getchar();}
    	while(isdigit(c)) {res=res*10+c-48; c=getchar();}
    	return res*w;
    }
    
    int T,n;
    char s[N];
    
    signed main() {
    	T=read();
    	while(T--) {
    		scanf("%lld%s",&n,s+1);
    		int l=0;
    		rep(i,1,n) {
    			if(s[i]=='?'&&s[i-1]!='?') l=i;
    			if(s[i]=='?'&&s[i+1]!='?') {
    				int r=i;
    				if(l==1) {
    					per(i,r,l) {
    						if(s[i+1]=='B') s[i]='R';
    						else s[i]='B';
    					}
    				} else if(r==n) {
    					rep(i,l,r) {
    						if(s[i-1]=='B') s[i]='R';
    						else s[i]='B';
    					}
    				} else {
    					while(l<=r) {
    						if(s[l-1]=='B') s[l++]='R';
    						else s[l++]='B';
    						if(s[r+1]=='B') s[r--]='R';
    						else s[r--]='B';
    					}
    				}
    			}
    		}
    		rep(i,1,n) putchar(s[i]); putchar('
    ');
    	}
    	return 0;
    }
    

    CF1559C

    发现有几种情况。

    • (a_1=1),那么直接从 (n+1 o 1 odots o n) 即可。
    • (a_n=0),那么直接从 (1 o dots o n o n+1) 即可。
    • 如果上面两种都不成立,必然存在相邻的两个使得 (a_i=0,a_{i+1}=1),直接在这两个中间插入一个 (n+1) 即可。
    #include<bits/stdc++.h>
    #define int long long
    #define rep(i,a,b) for(int i=(a);i<=(b);i++)
    #define per(i,a,b) for(int i=(a);i>=(b);i--)
    using namespace std;
    const int N=1e5+9;
    
    inline long long read() {
    	long long res=0, w=1; char c=getchar();
    	while(!isdigit(c)) {if(c=='-') w=-1; c=getchar();}
    	while(isdigit(c)) {res=res*10+c-48; c=getchar();}
    	return res*w;
    }
    
    int T,n,a[N];
    
    signed main() {
    	T=read();
    	while(T--) {
    		n=read(); 
    		rep(i,1,n) a[i]=read();
    		if(a[1]==1) {
    			printf("%lld ",n+1);
    			rep(i,1,n) printf("%lld ",i);
    			puts("");
    		} else if(a[n]==0) {
    			rep(i,1,n) printf("%lld ",i);
    			printf("%lld ",n+1);
    			puts("");
    		} else {
    			int pos=0;
    			rep(i,1,n-1) if(a[i]==0&&a[i+1]==1) {pos=i; break;}
    			rep(i,1,pos) printf("%lld ",i);
    			printf("%lld ",n+1);
    			rep(i,pos+1,n) printf("%lld ",i);
    			puts("");
    		}
    	}
    	return 0;
    }
    

    CF1559D

    两个放一起写吧。首先容易感性地理解发现,由于每次两边都减少一个连通块,并且都是减少 (u,v) 所在连通块,所以我们只要暴力枚举哪些点没联通然后直接连上就行了。这样就可以过 D1。

    D2 就比较有意思了。假设我们钦定一个中心点 (s)。那么首先两个森林中对于 (u) 如果 (s) 都和 (u) 不连通,那么必然能连。连完后还有些不连通的,我们发现对于点 (u,v),它们必然不会在两棵树上都与 (s) 联通。如果 (u) 在第一棵树上与 (s) 联通并且 (v) 在第二棵树上与 (s) 联通,那么我们必然能连接 ((u,v))(如果它们在任意一棵树上已经联通,那么必然导致存在一个点与 (s) 都联通)。然后我们找到这些点,匹配一下即可。

    #include<bits/stdc++.h>
    #define rep(i,a,b) for(int i=(a);i<=(b);i++)
    #define per(i,a,b) for(int i=(a);i>=(b);i--)
    using namespace std;
    const int N=1e5+9;
    typedef pair<int,int> pii;
    
    inline long long read() {
    	long long res=0, w=1; char c=getchar();
    	while(!isdigit(c)) {if(c=='-') w=-1; c=getchar();}
    	while(isdigit(c)) {res=res*10+c-48; c=getchar();}
    	return res*w;
    }
    
    int n,m1,m2,id1[N],id2[N],c1[N],c2[N],ans;
    void init(int *id) {rep(i,1,n) id[i]=i;}
    int find(int *id,int i) {return i==id[i]?i:id[i]=find(id,id[i]);}
    void unite(int *id,int u,int v) {id[find(id,u)]=find(id,v);}
    vector<pii>vec;
    vector<int>ar1,ar2;
    
    int main() {
    	n=read(), m1=read(), m2=read();
    	init(id1), init(id2);
    	rep(i,1,m1) {
    		int u=read(), v=read();
    		unite(id1,u,v);
    	}
    	rep(i,1,m2) {
    		int u=read(), v=read();
    		unite(id2,u,v);
    	}
    	int s=rand()%n+1;
    	rep(i,1,n) {
    		c1[i]=(find(id1,i)==find(id1,s));
    		c2[i]=(find(id2,i)==find(id2,s));
    	}
    	rep(i,1,n) if((find(id1,i)==find(id1,s))+(find(id2,i)==find(id2,s))==0)
    		vec.push_back(pii(s,i)), unite(id1,s,i), unite(id2,s,i);
    	rep(i,1,n) {
    		if(find(id1,i)!=find(id1,s)) ar1.push_back(i), unite(id1,s,i);
    		if(find(id2,i)!=find(id2,s)) ar2.push_back(i), unite(id2,s,i);
    	}
    	int sz=min(ar1.size(),ar2.size());
    	rep(i,0,sz-1) {
    		vec.push_back(pii(ar1[i],ar2[i]));
    	}
    	ans=vec.size();
    	printf("%d
    ",ans);
    	for(auto x:vec) printf("%d %d
    ",x.first,x.second);
    	return 0;
    }
    

    CF1559E

    小清新容斥 DP 题。考虑普通背包计数是 (O(nm)) 的。然后再看 GCD 的限制。对于这种东西,我们可以非常自然地想到容斥这个 GCD (d),容斥系数容易发现就是莫比乌斯函数。一个小优化,若有 (mu(d)=0) 那么我们可以直接跳过,可以优化一些常数。

    #include<bits/stdc++.h>
    #define rep(i,a,b) for(int i=(a);i<=(b);i++)
    #define per(i,a,b) for(int i=(a);i>=(b);i--)
    using namespace std;
    const int N=1e5+9,mod=998244353;
    
    inline long long read() {
    	long long res=0, w=1; char c=getchar();
    	while(!isdigit(c)) {if(c=='-') w=-1; c=getchar();}
    	while(isdigit(c)) {res=res*10+c-48; c=getchar();}
    	return res*w;
    }
    
    int n,m,pl[N],prr[N],l[N],r[N],f[N],s[N],pr[N],cnt,mu[N],vst[N],ans;
    
    void sieve(int n){
    	mu[1]=1;
    	for(int i=2;i<=n;i++){
    		if(!vst[i]) pr[++cnt]=i,mu[i]=-1;
    		for(int j=1;j<=cnt&&i*pr[j]<=n;j++){
    			vst[i*pr[j]]=1;
    			if(i%pr[j]==0){mu[i*pr[j]]=0;break;}
                mu[i*pr[j]]=-mu[i];
    		}
    	}
    }
    
    signed main() {
    	n=read(), m=read();
    	sieve(m);
    	rep(i,1,n) pl[i]=read(), prr[i]=read();
    	rep(d,1,m) if(mu[d]) {
    		rep(i,1,n) l[i]=(pl[i]+d-1)/d, r[i]=prr[i]/d;
    		int nm=m/d;
    		rep(j,0,nm) s[j]=1;
    		rep(i,1,n) {
    			rep(j,1,nm) f[j]=0;
    			rep(j,l[i],nm) {
    				f[j]=s[j-l[i]];
    				if(j-r[i]-1>=0) f[j]=(f[j]+mod-s[j-r[i]-1])%mod;
    			}
    			s[0]=0;
    			rep(j,1,nm) s[j]=(s[j-1]+f[j])%mod;
    		}
    		ans=(ans+mu[d]*s[nm])%mod;
    	}
    	ans=(ans+mod)%mod;
    	printf("%d
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    ZooKeeper实践:(1)集群管理
    删除重复数据只保留一条
    查询sqlserver 大小写
    字段按位数自动加空格
    批量更新数据遍历数据
    测试端口号是否开通
    收缩数据库
    插入ID=-1 的数据
    查询重复语句,多表查询
    oracle数据查询时间
  • 原文地址:https://www.cnblogs.com/TetrisCandy/p/15146216.html
Copyright © 2020-2023  润新知