Nim積


Nim積

https://www.cnblogs.com/zjp-shadow/p/10507030.html

對於高維的Nim游戲,可以拆分為單獨的每一維求Nim積.

下文以二維Nim積為例,定義為

\[x \otimes y = mex\{ (a \otimes b) \oplus (a \otimes y) \oplus(x \otimes b),0 \le a < x, 0 \le b < y \} \]

其中 \(\otimes\) 為nim積, \(\oplus\) 為異或.

性質

\[0 \otimes x = 0 \\ 1 \otimes x = x \\ x \otimes y = y \otimes x \\ (x \otimes y) \otimes z = x \otimes (y \otimes z) \\ x \otimes(y \oplus z) = (x \otimes y) \oplus(x \otimes z) \]

\(0\) 與任何數的Nim積為 \(0\) ,\(1\) 為單位元,滿足交換律,結合律,分配率.

費馬數

費馬數即 Fermat 2-power 數為形如 \(2^{2^n}\) 的數,其中 \(n \in \mathbb {N}\) ,對於費馬數 \(a\) 滿足

  1. 對於\(x<a\) ,有 \(a \otimes b = a \times b\)
  2. \(a \otimes a = \dfrac 32 a\)

二維Nim積的計算

\(f(x,y) = x \otimes y\) ,我們將 \(x,y\) 拆分為若干個二進制位計算,令 \(g(x,y) = 2^x \otimes 2^y\) ,則有

\[f(x,y) = \oplus_{u \in x,v\in y}g(u,v) \]

\(g(x,y)\) 的計算

現在要計算 \(g(x,y)=2^x \oplus 2^y\) ,那么對於 \(x,y\) 的最高位 \(k\) (即 \(x\) 的最高位和 \(y\) 的最高位中的較大值),有以下兩種情況

最高位均為1

\(M=2^{2^k},A=2^{x-2^k},B=2^{y-2^k}\) ,其中 \(M\) 為費馬數,且 \(M>A,M>B\) ,那么可以利用費馬數的性質進行如下推導

\[\begin{align} x \otimes y &= (A \times M) \otimes(B \times M) \\ &=(A \otimes M) \otimes (B \otimes M) \\ &= (M \otimes M) \otimes(A \otimes B) \\ &= (\dfrac 32M) \otimes (A \otimes B) \end{align} \]

最高位中有一個1,一個0

不妨設是 \(x\) 的最高位為 \(1\) ,設 \(M=2^{2^k},A=2^{x-2^k},B=2^y\) ,有 \(M>A,M>B\) ,則

\[\begin{align} x \otimes y &= (M \times A) \otimes B \\ &= (M \otimes A) \otimes B \\ &= M \otimes (A \otimes B) \end{align} \]


於是遞歸的思考上面的過程,可以得到這樣的式子

\[\begin{align} g(x,y) &= (\otimes_{k \in (x \ xor \ y)} 2^{2^k}) (\otimes_{k \in (x \ and \ y) } 3 \cdot 2^{2^k-1}) \\ &= (\prod_{k \in (x \ xor \ y)} 2^{2^k}) (\otimes_{k \in (x \ and \ y) } 3 \cdot 2^{2^k-1}) \end{align} \]

右邊的部分可以用 \(f(x,y)\) 進行遞歸計算

時間復雜度 \(O(\log ^2 n)\) .

HDU 3404 Switch lights

Snipaste_2020-05-15_21-01-16.png

Code

#include <cstdio>
#include <cstring>
#include <iostream>
#define debug(...) fprintf(stderr,__VA_ARGS__)
using namespace std;
const int maxn=1000+50;
int T;
int n;
int x[maxn],y[maxn];
int bit[25];
int g[25][25];
int F(int,int);
int G(int x,int y)
{
	if(x==0||y==0) return bit[x+y];
	if(~g[x][y]) return g[x][y];
	int &re=g[x][y]=1;
	for(int i=0,t=x^y;bit[i]<=t;++i) if(t&bit[i])
		re<<=bit[i];
	for(int i=0,t=x&y;bit[i]<=t;++i) if(t&bit[i])
		re=F(re,3*bit[bit[i]-1]);
	return re;
}
int F(int x,int y)
{
	if(!x||!y) return 0;
	if(x==1||y==1) return x*y;
	int re=0;
	for(int i=0;bit[i]<=x;++i) if(x&bit[i])
		for(int j=0;bit[j]<=y;++j) if(y&bit[j])
			re^=G(i,j);
	return re;
}
bool sol()
{
	int an=0;
	for(int i=1;i<=n;++i) an^=F(x[i],y[i]);
	return an;
}
void init()
{
	bit[0]=1;
	for(int i=1;i<=20;++i) bit[i]=bit[i-1]<<1;
	memset(g,-1,sizeof(g));
}
int main()
{
	init();
	scanf("%d",&T);
	for(int kase=1;kase<=T;++kase)
	{
		scanf("%d",&n);
		for(int i=1;i<=n;++i) scanf("%d%d",&x[i],&y[i]);
		puts(sol()?"Have a try, lxhgww.":"Don't waste your time.");
	}
	return 0;
}

另一種二維nim積的計算方法

https://codeforces.com/blog/entry/74214

計算 \(x \otimes y\) ,設 \(x=xa \cdot P+xb,y=ya \cdot P + yb\) ,其中 \(P\) 是一個盡量將 \(x,y\) 分為相同兩半的費馬數.

那么有

\[\begin{align} x \otimes y&=(xa \otimes P \oplus xb) \otimes (ya \otimes P \oplus yb) \\ &= (xa \otimes ya) \otimes(P \otimes P) \oplus ((xa \otimes yb) \oplus (xb \otimes ya)) \otimes P \oplus (xb \otimes yb) \end{align} \]

觀察發現,對於其中 \((xa \otimes yb) \oplus (xb \otimes ya)\) ,有

\[(xa \oplus xb) \otimes (ya \oplus yb) = ((xa \otimes yb) \oplus (xb \otimes ya)) \oplus (xa \otimes ya) \oplus (xb \otimes yb) \]

\(P \otimes P = \dfrac 32 P = P \oplus \dfrac P2\) .所以可以如下計算

ull nim[256][256]; // 記憶化
ull f(ull x,ull y,int len=32) {
    if(x==0||y==0) return 0;
    if(x==1||y==1) return x*y;
    if(len<=4&&nim[x][y]) return nim[x][y];
    ull xa=x>>len,xb=x^(xa<<len),ya=y>>len,yb=y^(ya<<len);
    ull a=f(xb,yb,len>>1),b=f(xa^xb,ya^yb,len>>1),c=f(xa,ya,len>>1),d=f(c,1ull<<len-1,len>>1);
    ull re=((b^a)<<len)^a^d;
    if(len<=4) nim[x][y]=re;
//	debug("%llu %llu %llu\n",x,y,re);
    return re;
}

由於 \(x,y\) 很快會變成 \(0\) ,所以速度遠遠快於上面的方法.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM