联考20200729 T2 划愤



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

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

直接膜拜大佬博客

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

Nim积运算集合中单位元是1,乘法运算集合中单位元也是1
(x,y<2^{2^k})时,(xotimes 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
");
	else printf("xiaoDwandanle
");
}

原文地址:https://www.cnblogs.com/Darknesses/p/13404396.html