心得:打这个比赛的时候由于读题,自己变成一个大傻逼了,反思了一晚上 ,确实还是自己做的不够好,下面我口胡一篇自己的对于这几个题的解答。
比赛地址传送门
开始了:
A
题意:给出长度为N 的数组和可以操作的最大次数,然后要求你找出
非负的最小的数组字典序,然后有一个操作,选择一个数组+1,一个数组-1,直到找到最小字典序,或者操作做完。题解:直接就是把所有的数字[1–n-1]这个范围的数字依次减 然后+到第N个数上,特别要小心一下中间的的过程可能初始就是为0
int ans[maxx]; int main(){ int t;cin>>t; while(t--){ int n,k;cin>>n>>k; mse(ans,-1); for(int i=1;i<=n;i++) cin>>ans[i]; int pos=1; for(int i=k;i>=1;i--){ if(ans[pos]>0) ans[pos]--,ans[n]++; else { while(ans[pos]==0) pos++; if(pos>=n) break; ans[pos]--,ans[n]++; } } for(int i=1;i<=n;i++) cout<<ans[i]<<" "; cout<<endl; } return 0; }
B
题意:给你N个数字,然后要求每次删除两个数增加在这个位置一个数字(这个数字是删除的两数的异或和),最终问你能不能找到长度大于等于2并且这个数组的所有数字相等
题解:既然要使这个数组全部相等,不能简单的定义为判断所有数异或==0,就可以找到了 ,这只是一种情况,譬如[3,3,3,0]这种情况也是满足的,那么换一个思维来看,是不是可以简单 的找一下前缀异或和,如果该数组可以满足题意,那么是不是最后一位数字起到了最关键的作用,找出前缀和=sum,若前面有相等的那么必然中间过程可以异或等于0,那么我们就可以直接判断最后sum的值,和前面所有异或为0的区间,能不能找到一个前缀和为sum的,若可以找到那么这个[1-N]某些局部区间异或值一定可以变成[sum,sum,sum]
int ans[maxx]; int main(){ int t;cin>>t; while(t--){ int n;cin>>n; int flag=0,pos=0; for(int i=1;i<=n;i++) cin>>ans[i]; for(int i=2;i<=n;i++){ ans[i]^=ans[i-1]; if(ans[i]==0) pos=i; } int a=ans[n]; for(int i=1;i<=pos;i++) if(ans[i]==ans[n]) flag=1; if(flag) cout<<"YES"<<endl; else cout<<"NO"<<endl; } return 0; }
C
题意:给你N个数字,然后问你是否现在这个数组分成2个集合 , 能够找到一种情况 可以使这两个集合总和一样,如果可以,那么删除一个最小的数,使得不满足这个情况。
题解:首先,我们可以得出一个结论,两个集合要想相等,那么必然这个数组总和是偶数,如果为奇数那就直接可以不用操作,那么我们来看如果为偶数的情况,我们可以使整个数组同时>>1.前提是所有的数组都可以除,那么是不是一定可以变成最简单数,这个操作对于答案没任何影响,比如【2,6,8,12】–> 【1,3,4,6】,最终可以分成2个为7的,那么这样使得数组最简化,然后我们可以判断一下,如果这个数组中,某个数>sum(总和)/2,这种情况也是不需要处理的,比如[1,1,1,1,12],接下来的这个就是关键了,这个真的是我没有想到的找法,我们现在不确定是否可以在这个序列中任意构成一个集合总和=sum/2,那么就要找一个完美的处理方法,我们可以使用01背包原理,来找,这样子就可以找出一种可以构成sum/2的总和值是否存在的情况,最后判断是否找到,找不到就可以不处理,否则就要处理一次
int dp[maxx]; int ans[maxx]; int main(){ int n;cin>>n; int sum=0; for(int i=1;i<=n;i++) cin>>ans[i]; int c=0,k=mod; for(int i=1;i<=n;i++){ c=0; int a=ans[i]; while(a%2==0){ a>>=1;c++;} k=min(c,k); } int flag=0; for(int i=1;i<=n;i++) {ans[i]=ans[i]>>k;sum+=ans[i];} if(sum&1) cout<<0<<endl; else{ flag=0; for(int i=1;i<=n;i++) if(ans[i]>sum/2) {flag=1;break;} if(flag) cout<<0<<endl; else{ int mn=mod,pos,vis=0; flag=0; for(int i=1;i<=n;i++){ if(ans[i]==sum/2) vis=1; if(mn>ans[i]&&ans[i]%2==1){mn=ans[i]; pos=i;} } if(vis) { mn=mod; flag=1; for(int i=1;i<=n;i++) if(mn>ans[i]){mn=ans[i]; pos=i;} } else{ for(int i=1;i<=n;i++) { for(int j=sum/2;j>=ans[i];j--) dp[j]=max(dp[j],dp[j-ans[i]]+ans[i]); } if(dp[sum/2]==sum/2) flag=1; } if(flag) cout<<1<<endl<<pos<<endl; else cout<<0<<endl; } } return 0; }