• 联考20200729 T2 划愤




    分析:
    (为什么我这种准退役选手要学这种神仙东西啊2333
    考场上直接暴力,暴力都拿不到分。。。
    我们先考虑这样一个问题:
    n*m的格子上亮着一些灯,两人轮流进行如下操作:
    选择一个矩形满足右下角的灯是亮的,将四个角的灯改变状态,无法操作者负

    如果这个游戏是一维的,我们选一个亮着的灯的位置\(n\)和前面一个灯翻转,相当于\(n\)个石子里取走一部分
    是一个简单的Nim游戏,初始状态所有亮着的灯,他们分别会代表一个子游戏各自独立
    现在游戏变成二维,一个位置与某三个位置翻转,这三个位置分别形成三个子游戏
    于是数学家们便引入了Nim积,能够很好地表达上面的游戏中每个点的SG计算方式,并从中发掘了一些数学性质使我们加速运算

    直接膜拜大佬博客

    (相信大家已经学会了\(O(log^2n)\)求某个位置的Nim积了2333
    掌握了Nim积的知识回来看这道题
    相当于游戏变成\(N\)维,一个位置与某\(2^N-1\)个位置翻转,分别形成\(2^N-1\)个子游戏
    二维Nim积\(x\otimes y\)拓展到\(N\)维就是\(a_1\otimes a_2\otimes ...\otimes a_N\)
    单个游戏的我们会求了,但是这里有\(N!\)个游戏,暴力不可接受
    看看这\(N!\)个游戏的形成方式,感觉跟行列式非常的像
    我们知道Nim积和异或运算满足交换律,结合律,分配率
    我们把行列式的加法重载为异或,乘法重载为Nim积,发现不会出现错误
    至于行列式里面的\(-1\),由于异或拥有很好地数学性质,其逆运算是他本身,\(-1\)直接可以忽略不计
    直接对原矩阵求重载运算后的行列式,就可以得到最终的SG了,不为0则先手胜
    现在还有最后一个问题,关于Nim积的逆元
    这个我不是很懂,我直接与质数取模乘法类比的(

    Nim积运算集合中单位元是1,乘法运算集合中单位元也是1
    \(x,y<2^{2^k}\)时,\(x\otimes y<2^{2^k}\)
    相当于\([0,2^{2^k})\)中的数Nim积后结果仍在\([0,2^{2^k})\)
    \([0,P)\)中的数在模\(P\)意义相乘后结果也在\([0,P)\)
    而模\(P\)意义下\(x^{-1}=x^{P-2}\)
    那么Nim积意义下\(x^{-1}=x^{2^{2^k}-2}\)
    (不是很懂,但是验证下来是对的,会做的大佬可以评论区大力D我

    复杂度\(O(n^3log^2A)\)

    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #include<queue>
    #include<set>
    #include<map>
    #include<vector>
    #include<string>
    
    #define maxn 155
    #define maxm (1<<13)
    #define INF 0x3f3f3f3f
    #define MOD 998244353
    #define ull unsigned long long
    
    using namespace std;
    
    inline long long getint()
    {
    	long long num=0,flag=1;char c;
    	while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
    	while(c>='0'&&c<='9')num=num*10+c-48,c=getchar();
    	return num*flag;
    }
    
    int n;
    ull a[maxn][maxn],f[maxm][maxm],M[10];
    bool vis[maxm][maxm];
    
    inline ull mul(ull x,ull y,int p=32)
    {
    	if(x>y)swap(x,y);
    	if(!x||!y)return 0;
    	if(x==1)return y;
    	if(y<maxm&&vis[x][y])return f[x][y];
    	ull A=x>>p;
    	ull B=x&((1ull<<p)-1);
    	ull P=y>>p;
    	ull Q=y&((1ull<<p)-1);
    	ull ap=mul(mul(A,P,p>>1),1ull<<p>>1,p>>1),bq=mul(B,Q,p>>1);
    	ull ret=ap^bq^((mul(A^B,P^Q,p>>1)^bq)<<p);
    	if(y<maxm)vis[x][y]=1,f[x][y]=ret;
    	return ret;
    }
    
    inline ull ksm(ull num,ull k)
    {
    	ull ret=1;
    	for(;k;k>>=1,num=mul(num,num))if(k&1)ret=mul(ret,num);
    	return ret;
    }
    
    inline ull getinv(ull x)
    {
    	ull tmp;
    	for(int i=0;i<=5;i++)
    		if(x>=M[i])tmp=M[i];
    		else{tmp=M[i];break;}
    	return ksm(x,tmp-2);
    }
    
    int main()
    {
    	ull k=1;M[0]=2;
    	for(int i=1;i<=8;i++)
    	{
    		k=k+k,M[i]=1;
    		for(int j=1;j<=k;j++)M[i]=M[i]+M[i];
    	}
    	n=getint();
    	for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)cin>>a[i][j];
    	for(int i=1;i<=n;i++)
    	{
    		int id=0;
    		for(int j=i;j<=n;j++)if(a[j][i]){id=j;break;}
    		if(!id)continue;
    		for(int j=i;j<=n;j++)swap(a[i][j],a[id][j]);
    		ull Inv=getinv(a[i][i]);
    		for(int j=i+1;j<=n;j++)if(a[j][i]!=0)
    		{
    			ull tmp=mul(a[j][i],Inv);
    			for(int k=i;k<=n;k++)a[j][k]^=mul(a[i][k],tmp);
    		}
    	}
    	ull ans=1;
    	for(int i=1;i<=n;i++)ans=mul(ans,a[i][i]);
    	if(ans)printf("xiaoDyingle\n");
    	else printf("xiaoDwandanle\n");
    }
    

  • 相关阅读:
    POJ2406【KMP-next数组】
    POJ2752【KMP-next数组含义】
    POJ3696【欧拉函数+欧拉定理】
    POJ3692【二分匹配】
    POJ3697【BFS】
    CodeForces599D【数学】
    CodeForces599C【贪心】
    HDU1829【种类并查集】
    HDU3038【种类并查集】
    POJ1182【种类并查集】
  • 原文地址:https://www.cnblogs.com/IzayoiDoyo/p/13404396.html
Copyright © 2020-2023  润新知