CF刷题G

1.1594D - The Number of Imposters(简单遍历图)

#include<bits/stdc++.h>
using namespace std;
const int maxn=2e6+5;
string s1="imposter",s2="crewmate";
int t,n,m,k,f,ans,p1,p2,a[maxn],vis[maxn],to[maxn],head[maxn],w[maxn],nex[maxn];
void add(int x,int y,int z){
	to[++k]=y;
	nex[k]=head[x];
	head[x]=k;
	w[k]=z;
}
void dfs(int x){
	vis[x]=1;
	for(int i=head[x];i;i=nex[i]){
		int y=to[i];
		if(vis[y]){
			if(a[y]!=w[i]^a[x])f=1;
			continue;
		}
		a[y]=a[x]^w[i];
		if(!vis[y]){
			if(a[y])p1++;
		    else p2++;
		}
		dfs(y);
	}
}

int main(){
	scanf("%d",&t);
	while(t--){
		f=k=ans=0;
		scanf("%d%d",&n,&m);
		for(int i=1;i<=n;i++)head[i]=vis[i]=0;
		for(int i=1,x,y,d;i<=m;i++){
			string z;
			cin>>x>>y>>z;
			if(z==s1)d=1;
			else d=0;
			add(x,y,d);
			add(y,x,d);
		}
		for(int i=1;i<=n;i++){
			if(!vis[i]){
				p1=0,p2=1;
				a[i]=0;
				dfs(i);
				ans+=max(p1,p2);
			}
		}
		if(f)printf("-1\n");
		else printf("%d\n",ans);
	}
}

2.C. Bakry and Partitioning(异或思维+简单树遍历)

#include<bits/stdc++.h>
using namespace std;
using ll=long long;
const int maxn=2e6+5;
int t,n,k,f;
ll sum,tot,a[maxn];
vector<int>mp[maxn];
void dfs(int x,int fa){
	for(auto y:mp[x]){
		if(y==fa)continue;
		dfs(y,x);
		a[x]^=a[y];
	}
	if(a[x]==sum){
		a[x]=0;
		tot++;
	}
}
int main(){
	scanf("%d",&t);
	while(t--){
		tot=sum=f=0;
		scanf("%d%d",&n,&k);
		for(int i=1;i<=n;i++){
			scanf("%lld",&a[i]);
			sum^=a[i];
			mp[i].clear();
		}
		for(int i=1,x,y;i<n;i++){
			scanf("%d%d",&x,&y);
			mp[x].push_back(y);
			mp[y].push_back(x);
		}
		if(sum==0)f=1;
		else if(k>=3)dfs(1,0);
		if(tot>=3)f=1;
		if(f)printf("YES\n");
		else printf("NO\n");
	}
}

3.F. Array Stabilization (AND version)(思维考虑专业对象)

#include<bits/stdc++.h>
using namespace std;
using ll=long long;
const int maxn=2e6+5;
int t,n,d,a[maxn];
struct node{
	int x,dep;
};
queue<node>p;
int main(){
	scanf("%d",&t);
	while(t--){
		int f=0,ans=0;
		scanf("%d%d",&n,&d);
		for(int i=0;i<n;i++){
		    scanf("%d",&a[i]);
		    if(a[i]==0)p.push({i,0});
	    }
	    while(!p.empty()){
	    	int x=p.front().x,dep=p.front().dep;
	    	p.pop();
	    	int y=(x+d)%n;
	    	if(a[y]){
	    		a[y]=0;
	    		p.push({y,dep+1});
	    		ans=max(ans,dep+1);
			}
		}
		for(int i=0;i<n;i++)
		    if(a[i])f=1;
		if(f)printf("-1\n");
		else printf("%d\n",ans);
	}
	
}

4.E. Permutation Shift(排列交换)

证明

#include<bits/stdc++.h>
using namespace std;
using ll=long long;
const int maxn=2e6+5;
int t,n,m,k,e1[maxn],e2[maxn],vis[maxn],b[maxn],p[maxn],ans[maxn],nex[maxn];
vector<int>mp[maxn];
void dfs(int x){
	vis[x]=1;
	for(auto y:mp[x]){
		if(!vis[y])dfs(y);
	}
}
bool check(int x){
	int res=0;
	for(int i=0;i<n;i++){
		mp[i].clear();
		vis[i]=0; 
	}
	for(int i=0;i<n;i++){
		nex[(i+x)%n]=i;
	}
	for(int i=0;i<n;i++){
		mp[nex[i]].push_back(b[i]);
		mp[b[i]].push_back(nex[i]);
	}
	for(int i=0;i<n;i++){
		if(!vis[i])dfs(i),res++;
	}
	return n-res<=m;
}
int main(){
	scanf("%d",&t);
	while(t--){
		k=0;
		scanf("%d%d",&n,&m);
		for(int i=0;i<n;i++){
			scanf("%d",&b[i]);
			p[--b[i]]=i;
			e1[i]=e2[i]=0;
		}
		for(int i=0;i<n;i++){
			int d=(p[i]-i+n)%n;
			e1[d]++;
		}
		for(int i=0;i<n;i++){
			if(e1[i]*3>=n)e2[i]=1;
		}
		for(int i=n-1;i>=0;i--){
			if(e2[i]){
				if(check(i))ans[++k]=i;
				if(k==3)break;
			}
		}
		printf("%d",k);
		for(int i=k;i;i--){
			printf(" %d",ans[i]);
		}
		printf("\n");
	}
}

5.D. Array Differentiation
题意:给出数组a[n],问能否构造数组b,使得ai=bj-bk (n<=10)
思路:
显然对每一对bj-bk连一条权值为ai的边,一定可以构成n个点n条边的有环图。对于环上权值ai,一定可以通过给ai带上正负号求和为0,ai符号为{1,-1,0}

#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+5;
int t,n,a[maxn];
int main(){
	scanf("%d",&t);
	while(t--){
		scanf("%d",&n);
		for(int i=1;i<=n;i++){
			scanf("%d",&a[i]);
		}
		int s=pow(3,n)-1,f=0;
		for(int i=1;i<=s;i++){
			int d=i,sum=0;
			for(int j=1;j<=n;j++){
				int p=d%3;
				if(p==1)sum+=a[j];
				else if(p==2)sum-=a[j];
				d/=3;
			}
			if(sum==0){
				f=1;
				break;
			}
		}
		if(f)printf("YES\n");
		else printf("NO\n");
	}
}

B. Strange Definition(分解质因子+思维)
给出 n n n个数,若 l c m ( x , y ) g c d ( x , y ) \frac{lcm(x,y)}{gcd(x,y)} gcd(x,y)lcm(x,y) 为完全平方数称 x , y x , y x,y是相邻的
每一秒都会发生以下的情况:
每个数被所有和自己相邻数字(包括自己)的乘积所替换
设为 d i d_i di和数字 a i a_i ai相邻数字的数量
给出 q q q组询问,问第 i i i秒最大的 d i d_i di
思路:
由于lcm(x,y)=x*y/gcd(x,y)

所以只要x∗y是完全平方数即可

如果xy是完全平方数,xz是完全平方数

那么yz是完全平方数,又因为x^2是完全平方数

那么y z也是完全平方数

所以相邻的元素都是彼此相邻的,可以分成若干个组

而x,y相邻的条件是对应的质因子质数奇偶性相同

那么可以质因子分解,保存对应的奇偶性作为分组的依据,使用map装起来

那么考虑每秒的变化,组内的数乘起来

如果组内的数个数为奇数,那么不会改变每个质因子的奇偶性质,分组不变

如果组内的数个数为偶数,一次变化过后所有的幂都变成了偶数,每个数都是完全平方数

一秒后,所有偶数组的个数都合并了

#include<bits/stdc++.h>
using namespace std;
using ll=long long;
const int maxn=1e6+5;
int t,n,cnt,q,vis[maxn],prime[maxn],a[maxn];
void getprime(){
	for(int i=2;i<=1e6;i++){
		if(!vis[i])prime[++cnt]=i;
		for(int j=1;j<=cnt&&i*prime[j]<=1e6;j++){
			vis[i*prime[j]]=1;
			if(i%prime[j]==0)break;
		}
	}
}
int main(){
	getprime();
	scanf("%d",&t);
	while(t--){
		scanf("%d",&n);
		a[n+1]=0;
		for(int i=1,x;i<=n;i++){
			a[i]=1;
			scanf("%d",&x);
			int d=1;
			if(!vis[x])a[i]=x;
			else{
				for(int j=1;j<=cnt;j++){
				    if(x%prime[j]==0){
					    int he=0;
					    while(x%prime[j]==0){
						    x/=prime[j];
						    he++;
					    }
					    if(he%2)a[i]*=prime[j];
				    }
				    if(x<1ll*prime[j]*prime[j])break;
				}
				if(x!=1)a[i]*=x;
			}
		}
		sort(a+1,a+1+n);
		int he=1,p1=0,p0=0,p2=0,k=0;
		for(int i=2;i<=n+1;i++){
			if(a[i]==a[i-1])he++;
			else {
				if(a[i-1]==1)p0=he;
				else if(he%2)p1=max(p1,he);
				else p2+=he,p1=max(he,p1);
				he=1;
			}
		}
		scanf("%d",&q);
		while(q--){
			ll x;
			scanf("%lld",&x);
			if(x==0)printf("%d\n",max(p0,p1));
			else printf("%d\n",max(p0+p2,p1));
		}
	} 
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值