[ZJOI2009]染色游戏
Description
一共n × m 个硬币,摆成n × m 的长方形。dongdong 和xixi 玩一个游戏, 每次可以选择一个连通块,并把其中的硬币全部翻转,但是需要满足存在一个 硬币属于这个连通块并且所有其他硬币都在它的左上方(可以正左方也可以正 上方),并且这个硬币是从反面向上翻成正面向上。dongdong 和xixi 轮流操作。 如果某一方无法操作,那么他(她) 就输了。dongdong 先进行第一步操作,假 设双方都采用最优策略。问dongdong 是否有必胜策略。
Input
第一行一个数T,表示他们一共玩T 局游戏。接下来是T 组游戏描述。每 组游戏第一行两个数n;m,接下来n 行每行m 个字符,第i 行第j 个字符如 果是“H” 表示第i 行第j 列的硬币是正面向上,否则是反面向上。第i 行j 列 的左上方是指行不超过i 并且列不超过j 的区域。
Output
对于每局游戏,输出一行。如果dongdong 存在必胜策略则输出“- -”(不含 引号) 否则输出“= =”(不含引号)。(注意输出的都是半角符号,即三个符号 ASCII 码分别为45,61,95)
Sample Input
32
3
HHH
HHH
2 3
HHH
TTH
2 1
T
H
3
HHH
HHH
2 3
HHH
TTH
2 1
T
H
Sample Output
= =
- -
- -
- -
- -
HINT
对于40% 的数据,满足1 ≤ n;m ≤ 5。
对于100% 的数据,满足1 ≤ n;m ≤ 100,1 ≤ T ≤ 50。
先考虑一维
SG[i]为单独考虑只有i是反面,其他都是正面的SG值,这样原情况可以转化为很多子游戏
假设要求SG[3]
也就是001
有这么几种:000 010 110
SG[3]=mex{0,2,2^1}=1
SG(4) = mex{0, 1, 1 XOR 2, 1 XOR 2 XOR 1} = 4;
SG(5) = mex(0, 4, 4 XOR 1, 4 XOR 1 XOR 2, 4 XOR 1 XOR 2 XOR 1) = 1;
枚举了很多SG发现SG[n]=lowbit(n)
将类似的方法拓展到2维:
要求SG[2][2],也就是
归纳得出,在i,j都大于1时,SG[i][j]=2i+j-2
在i或j为0时,为一维的算法
优于2200过大,所以用二进制存储
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 using namespace std; 7 struct Num 8 { 9 int a[201]; 10 }SG[101][101],ans; 11 int n,m,flag; 12 char s[102]; 13 Num operator ^(const Num &A,const Num &B) 14 {int i; 15 Num C; 16 memset(C.a,0,sizeof(C.a)); 17 for (i=0;i<=200;i++) 18 if (A.a[i]!=B.a[i]) C.a[i]=1; 19 return C; 20 } 21 int lowbit(int x) 22 { 23 return x&(-x); 24 } 25 void getSG() 26 {int i,j; 27 SG[1][1].a[0]=1; 28 for (i=2;i<=100;i++) 29 { 30 int x=lowbit(i); 31 for (j=0;j<=7;j++) 32 if ((1<<j)==x) 33 SG[1][i].a[j]=SG[i][1].a[j]=1; 34 } 35 for (i=2;i<=100;i++) 36 { 37 for (j=2;j<=100;j++) 38 { 39 SG[i][j].a[i+j-2]=1; 40 } 41 } 42 } 43 int main() 44 {int T,i,j; 45 cin>>T; 46 getSG(); 47 while (T--) 48 { 49 cin>>n>>m; 50 memset(ans.a,0,sizeof(ans.a)); 51 for (i=1;i<=n;i++) 52 { 53 scanf("%s",s+1); 54 for (j=1;j<=m;j++) 55 { 56 if (s[j]=='T') ans=ans^SG[i][j]; 57 } 58 } 59 flag=0; 60 for (i=0;i<=100;i++) 61 if (ans.a[i]) 62 {flag=1;break;} 63 if (flag) printf("-_-\n"); 64 else printf("=_=\n"); 65 } 66 }