【HDU5579 2015上海赛区G】【超级大讨论】Game of Arrays a[]+b[]+c[]有些位置可以减一,状态是否可能达成

来源:互联网 发布:md5是国产密码算法吗 编辑:程序博客网 时间:2024/05/10 14:37

 

Game of Arrays

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 14    Accepted Submission(s): 6


Problem Description
Tweek and Craig are good friends and always playing together. And they just invented a new game when doing their math homework.

First of all, they write three arrays A, B, and C, each with N numbers. Then on the black board, they write those arrays as

A+B=C


If the equation is satisfied, it means for each position i from 1 to N, there are Ai+Bi=Ci holds.

Of course, this equation is not always satisfied at the very beginning.

Fortunately, for arrays A, B and C, some numbers are changeable, while other's are not. Those changeable numbers' positions are determined before the game begins.

During the game, Tweek and Craig will take turns, trying to change a number from an array. Tweek plays first.

In each turn, the player can choose a changeable number from an array, and substract it by one. However, no negative numbers should appear, so the chosen number cannot be 0 before substraction.

Tweek's goal is to make the equation satisfied during the game, while Craig's goal is to prevent it to happen.

The game ends when the equation is satisfied (a win for Tweek) or there are no possible moves but still A+BC (means there is at least one i[1,N], where Ai+BiCi, which is a win for Craig).

Given A, B and C, and the position of changeable numbers for each array, your task is to determine the winner.
 

Input
First line contains an integer T, which indicates the number of test cases.

Every test case begins with an integers N, which is the length of array A, B and C.

The 2nd line and 3rd line describe the array A. The 2nd line contains N intergers A1, A2, , AN, indicating the elements in array A. The 3rd line contains Nintergers u1, u2, , uN, and ui is 1 if Ai is changeable, otherwise ui is 0.

The 4th line and 5th line describe the array B. The 4th line contains N intergers B1, B2, , BN, indicating the elements in array B. The 5th line contains Nintergers v1, v2, , vN, and vi is 1 if Bi is changeable,otherwise vi is 0.

The 6th line and 7th line describe the array C. The 6th line contains N intergers C1, C2, , CN, indicating the elements in array C. The 7th line contains Nintergers w1, w2, , wN, and wi is 1 if Ci is changeable,otherwise wi is 0.

 1T2000.

 for 75% data, 1N10.

 for 95% data, 1N50.

 for 100% data, 1N100.

 0Ai,Bi,Ci109.

 both ui,vi,wi is either 0 or 1.
 

Output
For every test case, you should output "Case #x: y", where x indicates the case number and counts from 1, and y is the winner of the game.
 

Sample Input
324 31 14 40 15 50 024 41 14 40 05 50 024 41 14 40 04 40 0
 

Sample Output
Case #1: TweekCase #2: CraigCase #3: Tweek
 

Source
2015ACM/ICPC亚洲区上海站-重现赛(感谢华东理工)
 


转载请务必注明出处,谢谢~~。


#include<stdio.h>#include<string.h>#include<ctype.h>#include<math.h>#include<iostream>#include<string>#include<set>#include<map>#include<vector>#include<queue>#include<bitset>#include<algorithm>#include<time.h>using namespace std;#define MS(x,y) memset(x,y,sizeof(x))#define MC(x,y) memcpy(x,y,sizeof(x))#define MP(x,y) make_pair(x,y)#define ls o<<1#define rs o<<1|1typedef long long LL;typedef unsigned long long UL;typedef unsigned int UI;template <class T1,class T2>inline void gmax(T1 &a,T2 b){if(b>a)a=b;}template <class T1,class T2>inline void gmin(T1 &a,T2 b){if(b<a)a=b;}const int N=100+5,M=0,Z=1e9+7,ms63=1061109567;int casenum,casei;int a[N],b[N],c[N];bool aa[N],bb[N],cc[N];int weak[N],str[N];int n;bool match(){int step=1;//step==1表示我们还有先手权int weaknum=0;LL strsum=0;for(int i=1;i<=n;++i){int tmp=abs(a[i]+b[i]-c[i]);if(aa[i]==0&&bb[i]==0&&cc[i]==0)//000{//状态固定if(a[i]+b[i]!=c[i])return 0;}if(aa[i]==1&&bb[i]==1&&cc[i]==1)//111{//状态稳定strsum+=tmp;}else if(aa[i]==1&&bb[i]==1&&cc[i]==0)//110{//状态非法if(a[i]+b[i]<c[i])return 0;//状态稳定if(c[i]==0)strsum+=tmp;//状态脆弱else weak[++weaknum]=tmp;}else if(aa[i]==0&&bb[i]==0&&cc[i]==1)//001{//状态非法if(a[i]+b[i]>c[i])return 0;//状态稳定if(a[i]==0&&b[i]==0)strsum+=tmp;//状态脆弱else weak[++weaknum]=tmp;}else if(aa[i]==1&&bb[i]==0&&cc[i]==0)//100{//状态非法if(a[i]+b[i]<c[i])return 0;//状态稳定if(b[i]==c[i])strsum+=tmp;//状态脆弱else weak[++weaknum]=tmp;}else if(aa[i]==1&&bb[i]==0&&cc[i]==1)//101{//状态稳定if(b[i]==0){strsum+=tmp;continue;}//状态非法if(b[i]>c[i])return 0;//c[]太小,式子必然不满足。if(a[i]+b[i]>c[i]+1)return 0;//这种情况Craig可以把c[]降到0,必然不满足if(a[i]+b[i]==c[i]+1)//这种情况必须一步到位{if(--step<0)return 0;}//状态脆弱这个情况状态脆弱是必然的int tmp=c[i]-(a[i]+b[i]);weak[++weaknum]=tmp;}}if(weaknum==0)return 1;else if(weaknum==1){if(strsum<=weak[1]+1)return 1;}else if(weaknum==2){int x=weak[1];int y=weak[2];if(strsum==0){if(abs(x-y)==1)return 1;}else if(strsum==1){if(abs(x-y)==0)return 1;}}else//当weaknum>2时,操作必须最多一步到位。令人惊奇的是,数据中竟然没有这个。{LL sum=strsum;for(int i=1;i<=weaknum;++i)sum+=abs(weak[i]);if(sum<=1)return 1;}return 0;}int main(){scanf("%d",&casenum);for(casei=1;casei<=casenum;++casei){scanf("%d",&n);for(int i=1;i<=n;++i)scanf("%d",&a[i]);for(int i=1;i<=n;++i)scanf("%d",&aa[i]);for(int i=1;i<=n;++i)scanf("%d",&b[i]);for(int i=1;i<=n;++i)scanf("%d",&bb[i]);for(int i=1;i<=n;++i)scanf("%d",&c[i]);for(int i=1;i<=n;++i)scanf("%d",&cc[i]);for(int i=1;i<=n;++i){if(a[i]==0&&aa[i]==1)aa[i]=0;if(b[i]==0&&bb[i]==1)bb[i]=0;if(c[i]==0&&cc[i]==1)cc[i]=0;if(aa[i]==0&&bb[i]==1){swap(a[i],b[i]);swap(aa[i],bb[i]);}}printf("Case #%d: %s\n",casei,match()?"Tweek":"Craig");}return 0;}/*【trick&&吐槽】1,我们队在上海,在138分钟的时候就做完了5题,而且5题都是一次AC,只有348分钟的罚时。好像排在前10.然后我的两个研究数据结构的队友就想出了D题的大体做法,然后开始写了。他俩足足写了2个半小时,一直写到最后都没有AC,我们就这样失掉了金牌。读题顺序,实在是太关键了。读到的题都是神题,读题和思考的时间都一去不返。赛场上,B题这么傻叉的题,我1个半小时才看到;G题这么适合我的题,也是3个小时之后才看到。当时已经想好的G题的大概做法,然而毕竟要考虑众多因素,担心漏考虑陷入坑里。而且队友正在自信满满地写D题,就一直没有写,而他们最后也没有给我留下时间写。2,然而,刚才重现赛的时候,把当时的想法写下来就AC了呀!刚写完急着去洗手间所以直接交了WA了一次,稍微debug了下就AC了呀T_T!当时赛场大家都是至少3A,平均5A,我要是不急着交就1A了啊!3,这道题确实是个超级大讨论!【题意】给你三个数列a[],b[],c[],权值在[0,1e9]之间。数列中的有些位置的数可以做-1操作,但是在任何时刻,数都不能为负。(类如aa[],如果aa[i]==1,表示我们可以对a[i]做操作;==0则表示不可以)Tweek先手,Tweek的任务是使得在某一时刻,有a[]+b[]=c[],所有位置都成立。Craig后手,Craig的任务是使得即时到最后时刻,都不能有a[]+b[]=c[],至少有一位不成立。【类型】超级大讨论【分析】我们对于某个位置p的a[p] b[p] c[p],其实一共只有8种情况。加上我们可以考虑等价化,其实只需要考虑6种情况。我们只要做适当讨论,即可AC这道题。我们用步骤一:预处理——1,等价化:{010}->{100},{011}->{101}2,特殊处理:if(aa[i]==1&&a[i]==0)aa[i]=0把实质不能修改的于bool数组上体现步骤二:枚举位置做判定,状态有这么几种——1,状态固定,即aa[p]==bb[p]==cc[p]==0,那么if(a[p]+b[p]!=c[p])return 0;2,状态稳定,即对于所有可做减法的位置,做减法操作到最后,一定会满足a[p]+b[p]=c[p]。而且因为操作到了最后,数已经变成了0,不再不可操作,所以会维持稳定状态。3,状态脆弱,即在某个瞬间会满足a[p]+b[p]=c[p],然而操作到最后,会不再满足要求。4,状态非法,对于这个,直接返回0即可。我们把达到稳定状态的所有步数记录在str[],和达到脆弱状态的所有步数记录在weak[]。个数分别是strnum和weaknum,总和分别是strsum和weaksum。然后——1,weaknum==0时,一定yes2,weaknum==1时,weaksum不能太大,最多只能比多strsum大1。否则会被减穿。3,weaknum==2时,strsum只能为0或1,strsum为0时,两个weak[]的步长之差要恰好为1strsum为1时,两个weak[]的步长之差要恰好为04,weaknum>2时,操作步长之和要最多为1,要求必须一步到位。有一种需要特殊照顾的情况aa[]bb[]cc[]101这时b[]==0是稳定状态。在b[]>0的条件下,aa[]+bb[]>cc[]+1是非法状态aa[]+bb[]==cc[]+1是个要求必须一步到位的状态,这个我恰好利用使得一个weak[]值变为-1,同时用step计数恰好可以做到这一点aa[]+bb[]<cc[]也是必然的脆弱状态,一样记录步数好啦。这道题细节很多,然而并不是不可写。有了状态的定义(非法,固定,稳定,脆弱),再加上一些讨论,这道题就做完啦!再次表示怨念TwT!想出算法竟然没得写>_<!唉=w=,我这个两个药丸队友,信任他俩果然是自寻死路啊。【数据】input31 1 11 1 11 1 11 1 12 2 21 1 1outputTweek*/


#include<stdio.h>#include<string.h>#include<ctype.h>#include<math.h>#include<iostream>#include<string>#include<set>#include<map>#include<vector>#include<queue>#include<bitset>#include<algorithm>#include<time.h>using namespace std;#define MS(x,y) memset(x,y,sizeof(x))#define MC(x,y) memcpy(x,y,sizeof(x))#define MP(x,y) make_pair(x,y)#define ls o<<1#define rs o<<1|1typedef long long LL;typedef unsigned long long UL;typedef unsigned int UI;template <class T1,class T2>inline void gmax(T1 &a,T2 b){if(b>a)a=b;}template <class T1,class T2>inline void gmin(T1 &a,T2 b){if(b<a)a=b;}const int N=100+5,M=0,Z=1e9+7,ms63=1061109567;int casenum,casei;int a[N],b[N],c[N];int aa[N],bb[N],cc[N];int weak[N],str[N];int n;bool match(){//检测是否初始即可达bool nowIcan=1;for(int i=1;i<=n;++i)if(a[i]+b[i]!=c[i])nowIcan=0;if(nowIcan==1)return 1;int step=1;//step表示我们是否有先手操作机会int strnum=0;int weaknum=0;for(int i=1;i<=n;++i){int tmp=abs((a[i]+b[i])-c[i]);if(aa[i]==0&&bb[i]==0&&cc[i]==0)//000{//状态固定if(a[i]+b[i]!=c[i])return 0;}if(aa[i]==1&&bb[i]==1&&cc[i]==1)//111{//状态稳定int tmp=abs(a[i]+b[i]-c[i]);if(tmp)str[++strnum]=tmp;}else if(aa[i]==1&&bb[i]==1&&cc[i]==0)//110{//状态非法if(a[i]+b[i]<c[i])return 0;int tmp=a[i]+b[i]-c[i];//状态稳定if(c[i]==0){if(tmp)str[++strnum]=tmp;}//状态脆弱else{weak[++weaknum]=tmp;}}else if(aa[i]==0&&bb[i]==0&&cc[i]==1)//001{//状态非法if(a[i]+b[i]>c[i])return 0;int tmp=c[i]-(a[i]+b[i]);//状态稳定if(a[i]==0&&b[i]==0){if(tmp)str[++strnum]=tmp;}//状态脆弱else {weak[++weaknum]=tmp;}}else if(aa[i]==1&&bb[i]==0&&cc[i]==0)//100{//状态非法if(a[i]+b[i]<c[i])return 0;int tmp=a[i]+b[i]-c[i];//状态稳定if(b[i]==c[i]){if(tmp)str[++strnum]=tmp;}//状态脆弱else{weak[++weaknum]=tmp;}}else if(aa[i]==1&&bb[i]==0&&cc[i]==1)//101{//状态稳定if(b[i]==0){int tmp=abs(a[i]-c[i]);if(tmp)str[++strnum]=tmp;continue;}//状态非法if(b[i]>c[i])return 0;//c[]太小,式子必然不满足。if(a[i]+b[i]>c[i]+1)return 0;//这种情况对方可以把c[]降到0if(a[i]+b[i]==c[i]+1)//这种情况必须一步到位{if(--step<0)return 0;else --a[i];}//这个情况状态脆弱是必然的int tmp=c[i]-(a[i]+b[i]);weak[++weaknum]=tmp;}}LL strsum=0;for(int i=1;i<=strnum;++i)strsum+=str[i];LL weaksum=0;for(int i=1;i<=weaknum;++i)weaksum+=weak[i];LL totsum=strsum+weaksum;if(step==1)//我现在是先手{if(totsum<=1)return 1;//最多一步到位if(weaknum==0)return 1;if(weaknum==1){if(strsum<=weaksum+1)return 1;else return 0;}else if(weaknum==2){int x=weak[1];int y=weak[2];if(strsum==0){if(abs(x-y)==1)return 1;else return 0;}else if(strsum==1){if(abs(x-y)==0)return 1;else return 0;}else return 0;}else return 0;}else //我现在是后手{if(totsum==0)return 1;//初始状态即到位if(weaknum==0)return 1;if(weaknum==1){if(strsum<=weaksum)return 1;else return 0;}else if(weaknum==2){int x=weak[1];int y=weak[2];if(strsum==0){if(abs(x-y)==0)return 1;else return 0;}else return 0;}else return 0;}}void fre(){freopen("c://test//input.in","r",stdin);freopen("c://test//output.out","w",stdout);}int main(){scanf("%d",&casenum);for(casei=1;casei<=casenum;++casei){scanf("%d",&n);for(int i=1;i<=n;++i)scanf("%d",&a[i]);for(int i=1;i<=n;++i)scanf("%d",&aa[i]);for(int i=1;i<=n;++i)scanf("%d",&b[i]);for(int i=1;i<=n;++i)scanf("%d",&bb[i]);for(int i=1;i<=n;++i)scanf("%d",&c[i]);for(int i=1;i<=n;++i)scanf("%d",&cc[i]);for(int i=1;i<=n;++i){if(a[i]==0&&aa[i]==1)aa[i]=0;if(b[i]==0&&bb[i]==1)bb[i]=0;if(c[i]==0&&cc[i]==1)cc[i]=0;if(aa[i]==0&&bb[i]==1){swap(a[i],b[i]);swap(aa[i],bb[i]);}}printf("Case #%d: %s\n",casei,match()?"Tweek":"Craig");}return 0;}


0 0