Codeforces Round #717 (Div. 2)A-B详解

Posted 尘封陌路

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codeforces Round #717 (Div. 2)A-B详解相关的知识,希望对你有一定的参考价值。

题目链接:https://codeforces.com/contest/1516

A.Tit for Tat


题意:给定一个数组,然后再给定n和k。你可以执行操作如下:
给任意两个不同的元素(下标不同)一个加上1,一个减掉1
最多执行k次这样的操作,并且序列中不能出现负数。请你给出一个字典序最小的数组。

字典序:参考字符串的字典序比较。

思路
1.既然要字典序最小,那么 要让前面的数尽可能的小,那么我们就尽可能的减掉当前最前面的数,给最后面的数加1。如果到0了,就下一个数。当然,k次用完了就退出了。然后要保持没有负数。


AC代码:

#include<bits/stdc++.h>
using namespace std;
const int N=220;
int n,k;
int a[N];
int t;
int main()

	cin>>t;
	while(t--)
	
		cin>>n>>k;
		for(int i=1;i<=n;i++) cin>>a[i];
		for(int i=1;i<=n;i++)
		
			if(a[i]==0||i==n) continue;
			while(a[i]>0&&k>0)
			
				a[i]--;
				a[n]++;k--;
			
		
		for(int i=1;i<=n;i++) cout<<a[i]<<" ";
		cout<<endl;
	
	return 0;


B–AGAGA XOOORRR

题意:给你一个序列,你可以执行以下操作:把*相邻相邻相相邻的两个数异或(^),然后生成新的数。问你是否能通过一系列这样的操作,使得序列中满足元素都相等,且元素要满足大于等于2

关于异或

  1. (X^Y) ^Z == X^(Y ^Z)
  2. X^X=0 , X^0=X, X^X ^X=X.

思路重点:

(结论1)我们从末态出发,即最终的状态是序列都是同一个数。那么这个序列的长度要么是2,要么是3。

证明:因为,X^X=0,比如当前长度为4,序列为【X,X,X,X】,我们可以通过把后两个X ^X=0,序列就变成【X,X,0】,然后才把X ^ 0=X,于是,序列就变成了【X,X】 。奇数的情况同理。

2.当序列为偶数的那种情况,我们可以发现,如果序列可以构成相同,即最终状态为偶数个X,那么我们把这么多个X一起异或,即【X^X ^X ^X…】,那么最终一定是0,
所以当最终异或和为0的序列一定可以


讨论最终长度为奇数的情况
3,当序列为奇数的情况时,我们可以发现,序列的异或和为一个数Y(n为奇数,即n=2*k+1,k对的偶数异或都为0),所有最终为一堆0和一个数Y,如果序列可以满足,那么最终的数就是Y。

4.又因为最终需要大于等于2个数,相等所以我们只需要判断这里序列是否能够化成长度大于等于2且元素都相等的序列,即是否能找到2个及以上的Y。

实现

前缀异或 ans[i]=ans[i-1]^a[i]。


AC代码:(注释)

#include<bits/stdc++.h>
using namespace std;
int t,n;
int a[2100];
int main()

   
    cin>>t;
    while(t--)
    
        cin>>n;
        for(int i=0;i<n;i++)
        
            cin>>a[i];
        
        int ans = 0;
        for(int i=0;i<n;i++)
        
            ans = ans^a[i]; 
        
        if(ans == 0)
        
            cout<<"YES\\n";continue;
        else
        
            int temp = 0;
            int count = 0;
            for(int i=0;i<n;i++)
            
                temp = temp^a[i];//异或前缀 
                if(temp == ans)
                
                    count++; 
                    temp = 0;//满足的时候让他归0,可以理解把奇数凑成偶数,或者当前区间满足,找下个区间的时候从初始态开始异或。 
                
            //cnt就是记录最后剩下的数是不是大于2,已知最后一个数是Y,那么最少在前面再找一个Y即可。 
            if(temp == 0 && count>1 ) cout<<"YES\\n";
            else cout<<"NO\\n";
        
    
    

    return 0;

解法二

同样的,既然要使最终元素都相同。
那么,一定是若干个区间生成相同的数,组成的序列。
例如一个序列为【A,B,C,D,E,F】
那么在异或计算下可以是【A,B】=X,【C,D,E】=X,【F】=X。
再根据上面所讲,

要么分成2个区间,要么分成3个区间

异或前缀的运用

==类似于前缀和求区间【L,R】的和,区间【L,R】的异或和也可以通过
f[R]^f[L-1]。求得。

区间[L,R]异或和为 f[R]^f[L-1]

所以,我们把前缀异或和数组处理好后,直接枚举区间不就行了。

枚举2个区间1个for,枚举3个区间2个for,我这里一起处理了

AC代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e3+10;
map<ll,ll> mp;
ll a[N];
ll ans[N];
ll ans2[N];
int t;
int n;
void solve()

	if(n==1)
	
		cout<<"NO"<<endl;return;
	
	for(int i=1;i<=n;i++)
	
		for(int j=i;j<=n;j++)
		
			if(i==j&&ans[i]==(ans[n]^ans[i])) // [1,i] 和[i+1,n] 这两个区间。 
		
			cout<<"YES"<<endl;return;
		
		if(i!=j&&ans[i]==(ans[n]^ans[j])&&(ans[i]==(ans[i]^ans[j]))) //[1,i] 和 [i+1,j] 和 [j+1,n] 3个区间 
			
				cout<<"YES"<<endl;
				return ;
			   
		
	
	
	cout<<"NO"<<endl;
	return ;
	 

int main()

	cin>>t;
	while(t--)
	
		scanf("%d",&n);
		ll res=0;
		for(int i=1;i<=n;i++)
		
		scanf("%lld",&a[i]);
		res=res*a[i]; 
		ans[i] = ans[i-1] ^ a[i];
		
		solve();
	
	
	return 0;


C代码

AC代码

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int f[N];
int a[N];
int t,n;
int sum;
bool check()

	f[0]=1;
	for(int i=1;i<=n;i++)
	
		for(int j=N;j>=0;j--)
		
			f[j+a[i]]+=f[j];
		
	
//	printf("f[sum/2]===%d \\n",f[sum/2]);
	if(f[sum/2]) return false;
	return true;

int main()

	
		cin>>n;
		//int sum=0;
		for(int i=1;i<=n;i++)
		
			cin>>a[i];
		
		int k=a[1];
		for(int i=2;i<=n;i++)
		
			k=__gcd(k,a[i]);
		
		for(int i=1;i<=n;i++)
		
			a[i]/=k;sum+=a[i];
		
	//	printf("k===%d \\n",k);
		if(sum%2==1)
		
			cout<<"0"<<endl;return 0;
		
		else
		
			int st;//下标
		//	printf("st===%d \\n",st);
			for(int i=1;i<=n;i++)
			
				if(a[i]%2==1)
				
					st=i;
				
			
		//	printf("st===%d \\n",st);
	//		printf("chek=== %d\\n",check());
			if(check()==1) 
			
				cout<<"0"<<endl;
			
			else
			
				cout<<"1"<<endl;
				cout<<st<<endl;
			
		
		return 0;
	

以上是关于Codeforces Round #717 (Div. 2)A-B详解的主要内容,如果未能解决你的问题,请参考以下文章

Codeforces Round #717 (Div. 2)-A. Tit for Tat-题解

区间倍增dpD. Cut——Codeforces Round #717 (Div. 2)

Codeforces Round #717 (Div. 2)-C. Baby Ehab Partitions Again-题解

Codeforces Round #717 (Div. 2)-B. Maximum Cost Deletion-题解

Codeforces Round #717 (Div. 2)-B. Maximum Cost Deletion-题解

Codeforces Round #717 (Div. 2)-C. Baby Ehab Partitions Again-题解