UVa10561 Treblecross
博弈 sg函数
如果能一步取胜的话,直接扫一遍,找出所有能一步取胜的位置输出。
否则枚举放‘X’的位置,计算剩下空区间的SG函数的异或和,若为0,则该位置可以作为答案。
计算空区间时要刨去X旁边的两个空(放在这里必败) 例如.X.....X.这一区段的可用长度为3
SG函数的预处理还不太理解
↓那个pd()并没有用到
1 /*by SilverN*/ 2 #include<iostream> 3 #include<algorithm> 4 #include<cstring> 5 #include<cstdio> 6 #include<cmath> 7 using namespace std; 8 const int mxn=210; 9 char s[mxn]; 10 int n,f[mxn]; 11 inline bool pd(){ 12 for(int i=2;i<n;i++){ 13 if(s[i-1]=='X' && s[i]=='X' && s[i+1]=='X')return 1; 14 } 15 return 0; 16 } 17 inline bool check(int pos){ 18 if(s[pos+1]=='X'){ 19 if(s[pos-1]=='X' || s[pos+2]=='X')return 1; 20 } 21 else if(s[pos-1]=='X'){ 22 if(pos>2 && s[pos-2]=='X')return 1; 23 } 24 return 0; 25 } 26 inline bool ar(int p){ 27 for(int i=max(1,p-2);i<=p+2;i++)if(s[i]=='X')return 1; 28 return 0; 29 } 30 bool calc(){ 31 int i,j,len=0; 32 int res=0; 33 for(i=1;i<=n;i++){ 34 if(ar(i)){ 35 res^=f[len]; len=0; 36 } 37 else len++; 38 } 39 res^=f[len]; 40 return res; 41 } 42 int ans[mxn],cnt=0; 43 void solve(){ 44 cnt=0; 45 int i,j; 46 for(i=1;i<=n;i++){ 47 if(s[i]!='.')continue; 48 if(check(i)){ 49 for(j=i;j<=n;j++) 50 if(s[j]=='.' && check(j)){ans[++cnt]=j;} 51 return; 52 } 53 } 54 if(calc()){ 55 for(i=1;i<=n;i++){ 56 if(!ar(i)){ 57 s[i]='X'; 58 if(!calc()){ 59 ans[++cnt]=i; 60 } 61 s[i]='.'; 62 } 63 } 64 } 65 return; 66 } 67 int vis[mxn]; 68 void init(){//处理sg函数 69 int i,j,x; 70 f[1]=f[2]=1; 71 for(i=3;i<mxn;i++){ 72 memset(vis,0,sizeof vis); 73 for(j=1;j*2<=i+1;j++){ 74 x=f[i-j-2];//去掉边界两个空位 75 if(j>3)x^=f[j-3]; 76 vis[x]=1; 77 } 78 for(j=0;;j++){if(!vis[j]){f[i]=j;break;}} 79 } 80 return; 81 } 82 int main(){ 83 int T;scanf("%d",&T); 84 init(); 85 while(T--){ 86 memset(s,0,sizeof s); 87 scanf("%s",s+1); 88 n=strlen(s+1); 89 solve(); 90 if(cnt){ 91 printf("WINNING\n"); 92 for(int i=1;i<cnt;i++){ 93 printf("%d ",ans[i]); 94 } 95 printf("%d\n",ans[cnt]); 96 } 97 else printf("LOSING\n\n"); 98 } 99 return 0; 100 }
本文为博主原创文章,转载请注明出处。