1 条题解
-
0
有 个棋盘可以操作,且操作没有顺序,那么这个题明显只能用 SG 函数做。
考虑单个棋盘的 SG 函数值,容易发现两个行或两个列交换后与原棋盘等价,那么我们一定可以将 平移到左上角 的区域内。发现将棋盘转置也没有影响,于是发现初始等价类只有 种。分别为:
0: 000 111 111 1: 001 011 111 2: 011 101 110 3: 001 110 111发现进行转移时还会有其他等价类,可以发现还有以下几种:
4: 001 111 111 5: 011 111 111 6: 011 101 111 7: 111 111 111一个状态的 SG 函数只与当前行列数和类型有关,那么直接对 分讨转移即可,采用记搜会好写一点(可能吧)。边界非常多,注意分讨精细。因为发现转移不会超过 种,那么 SG 函数值不超过 ,计算 可以用位运算写,时空复杂度比较小。
总时间复杂度为巨大(约 倍)常数的 。
#include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; typedef unsigned char uc; char *p1,*p2,buf[100010]; #define gc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++) int read(){ int x=0; char c=gc(); while(c<48)c=gc(); while(47<c)x=(x<<3)+(x<<1)+(c&15),c=gc(); return x; } const size_t S=4095; uc SG[510][510][8],vs[510][510][8]; /* 0: 000 1: 00 0 2: 0 0 0 3: 00 0 4: 00 5: 0 6: 0 0 7: 1 */ void add(size_t&x,uc y){ x&=1<<y^S; } uc solve(int n,int m,uc o){ if(!n||!m)return 0; if(vs[n][m][o])return SG[n][m][o]; vs[n][m][o]=1; if(n==1){ if(m==3&&!o)return SG[n][m][o]; if(m==2&&o==4)return SG[n][m][o]; if(m==1&&o==5)return SG[n][m][o]; } size_t ans=S; switch(o){ case 5: if(m!=1)add(ans,solve(n-1,m,7)); if(n!=1)add(ans,solve(n,m-1,7)); add(ans,solve(n-1,m-1,7)); case 7: add(ans,solve(n-1,m-1,o)); add(ans,solve(n-1,m,o)); add(ans,solve(n,m-1,o)); break; case 6: if(n!=2)add(ans,solve(n-1,m,o)); if(m!=2)add(ans,solve(n,m-1,o)); if(n!=2&&m!=2)add(ans,solve(n-1,m-1,o)); add(ans,solve(n-1,m,5)); add(ans,solve(n,m-1,5)); add(ans,solve(n-1,m-1,5)); add(ans,solve(n-1,m-1,7)); break; case 4: add(ans,solve(n-1,m,o)); if(m!=2){ add(ans,solve(n-1,m-1,o)); add(ans,solve(n,m-1,o)); } if(n!=1)add(ans,solve(n,m-1,5)); if(m!=2)add(ans,solve(n-1,m,7)); add(ans,solve(n-1,m-1,5)); add(ans,solve(n-1,m-1,7)); break; case 3: if(n!=2){ add(ans,solve(n-1,m,o)); add(ans,solve(n-1,m-1,6)); } if(m!=3)add(ans,solve(n,m-1,o)); if(n!=2&&m!=3)add(ans,solve(n-1,m-1,o)); add(ans,solve(n-1,m,4)); add(ans,solve(n-1,m,5)); add(ans,solve(n,m-1,6)); add(ans,solve(n,m-1,4)); add(ans,solve(n-1,m-1,4)); add(ans,solve(n-1,m-1,7)); add(ans,solve(n-1,m-1,5)); break; case 2: if(n!=3)add(ans,solve(n-1,m,o)); if(m!=3)add(ans,solve(n,m-1,o)); if(n!=3&&m!=3)add(ans,solve(n-1,m-1,o)); add(ans,solve(n-1,m,6)); add(ans,solve(n,m-1,6)); add(ans,solve(n-1,m-1,6)); add(ans,solve(n-1,m-1,5)); break; case 1: if(n!=2){ add(ans,solve(n-1,m,o)); add(ans,solve(n,m-1,5)); add(ans,solve(m-1,n-1,4)); } if(m!=2){ add(ans,solve(n,m-1,o)); add(ans,solve(n-1,m,5)); add(ans,solve(n-1,m-1,4)); } if(n!=2&&m!=2)add(ans,solve(n-1,m-1,o)); if(n!=2||m!=2)add(ans,solve(n-1,m-1,7)); add(ans,solve(n-1,m,4)); add(ans,solve(m-1,n,4)); add(ans,solve(n-1,m-1,5)); break; default: add(ans,solve(n-1,m,o)); if(m!=3){ add(ans,solve(n,m-1,o)); add(ans,solve(n-1,m-1,o)); add(ans,solve(n-1,m,7)); } if(n!=1)add(ans,solve(n,m-1,4)); add(ans,solve(n-1,m-1,4)); add(ans,solve(n-1,m-1,7)); } return SG[n][m][o]=__builtin_ctz(ans); } int main(){ int k=read(),n,m,x1,x2,x3,y1,y2,y3; uc ans=0; while(k--){ n=read(); m=read(); x1=read(); y1=read(); x2=read(); y2=read(); x3=read(); y3=read(); if(x1==x2&&x2==x3)ans^=solve(n,m,0); else if(y1==y2&&y2==y3)ans^=solve(m,n,0); else if(x1!=x2&&x1!=x3&&x2!=x3) if(y1!=y2&&y2!=y3&&y1!=y3)ans^=solve(n,m,2); else ans^=solve(m,n,3); else if(y1!=y2&&y1!=y3&&y2!=y3)ans^=solve(n,m,3); else ans^=solve(n,m,1); } puts(ans?"OvO":"QAQ"); return 0; }
- 1
信息
- ID
- 7433
- 时间
- 2000ms
- 内存
- 512MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者