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。
关于异或
- (X^Y) ^Z == X^(Y ^Z)
- 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-题解