1 条题解

  • 0
    @ 2026-5-13 8:29:40

    kk 个棋盘可以操作,且操作没有顺序,那么这个题明显只能用 SG 函数做。

    考虑单个棋盘的 SG 函数值,容易发现两个行或两个列交换后与原棋盘等价,那么我们一定可以将 00 平移到左上角 3×33\times3 的区域内。发现将棋盘转置也没有影响,于是发现初始等价类只有 44 种。分别为:

    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 函数只与当前行列数和类型有关,那么直接对 SGn,m,oSG_{n,m,o} 分讨转移即可,采用记搜会好写一点(可能吧)。边界非常多,注意分讨精细。因为发现转移不会超过 1111 种,那么 SG 函数值不超过 1111,计算 mex\operatorname{mex} 可以用位运算写,时空复杂度比较小。

    总时间复杂度为巨大(约 6060 倍)常数的 O(nm+k)O(nm+k)

    #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
    上传者