bzoj 4589 Hard Nim

这里用 \(\oplus\) 表示 \(xor\) 运算 或 异或卷积.

  • 众所周知,\(Nim\) 博弈的结论:当且仅当 \(a_1\oplus a_2 \oplus \dots \oplus a_n=0\) 时,后手必胜,否则先手必胜.
  • 考虑构造一个数列 \(a,a_i=1\) 当且仅当 \(i\) 为小于等于 \(m\) 的质数,否则 \(a_i=0\) .
  • 如果 \(n=2\) ,令 \(b=a\oplus a,b_0\) 即为答案.可以推广, \(n\) 堆石头,就令 \(n\)\(a\) 连续做异或卷积,最后的 \(b_0\) 即为答案.
  • 这两步的结论(大概)可以通过结合 \(Nim\) 博弈的结论和异或卷积的定义,感性理解得出.
  • 注意到:

\[FWT(A\oplus B \oplus C)=FWT(IFWT(FWT(A)\times FWT(B)))\times FWT(C)\\ =FWT(A)\times FWT(B)\times FWT(C)\\ =FWT(A)\times( FWT(B)\times FWT(C)) \]

  • 所以可以算出 \(FWT(a)\) 后,令每个 \(a_i=a_i^n\) ,再对 \(a\)\(IFWT\) ,得到的 \(a_0\) 即为答案.
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define mp make_pair
#define pii pair<int,int>
inline int read()
{
	int x=0;
	bool pos=1;
	char ch=getchar();
	for(;!isdigit(ch);ch=getchar())
		if(ch=='-')
			pos=0;
	for(;isdigit(ch);ch=getchar())
		x=x*10+ch-'0';
	return pos?x:-x;
}
const int P=1e9+7;
const int inv2=500000004;
inline int add(int a,int b)
{
	return (a + b) % P;
}
inline int mul(int a,int b)
{
	return 1LL * a * b % P;
}
int fpow(int a,int b)
{
	int res=1;
	while(b)
		{
			if(b&1)
				res=mul(res,a);
			a=mul(a,a);
			b>>=1;
		}
	return res;
}
const int MAXM=5e4+10;
int prime[MAXM],cnt=0,ism[MAXM];
void init_prime()
{
	for(int i=2;i<=50000;++i)
		{
			if(!ism[i])
				prime[++cnt]=i;
			for(int j=1;j<=cnt && i*prime[j]<=50000;++j)
				{
					ism[i*prime[j]]=1;
					if(i%prime[j]==0)
						break;
				}
		}
}
void FWT_xor(int *a,int n)
{
	for(int l=2;l<=n;l<<=1)
		{
			int m=l>>1;
			for(int *p=a;p!=a+n;p+=l)
				{
					for(int i=0;i<m;++i)
						{
							int x0=p[i],x1=p[i+m];
							p[i]=add(x0,x1);
							p[i+m]=add(x0,P-x1);
						}
				}
		}
}
void IFWT_xor(int *a,int n)
{
	for(int l=2;l<=n;l<<=1)
		{
			int m=l>>1;
			for(int *p=a;p!=a+n;p+=l)
				{
					for(int i=0;i<m;++i)
						{
							int x0=p[i],x1=p[i+m];
							p[i]=mul(add(x0,x1),inv2);
							p[i+m]=mul(add(x0,P-x1),inv2);
						}
				}
		}
}
int n,m;
int a[MAXM<<1];
int main()
{
	init_prime();
	while(~scanf("%d %d",&n,&m))
		{
			int N=1;
			while(N<=m)
				N<<=1;
			memset(a,0,sizeof a);
			for(int i=2;i<=m;++i)
				a[i]=(!ism[i]);
			FWT_xor(a,N);
			for(int i=0;i<N;++i)
				a[i]=fpow(a[i],n);
			IFWT_xor(a,N);
			cout<<a[0]<<endl;
		}	
	return 0;
}

相关文章:

  • 2022-02-05
  • 2022-12-23
  • 2022-12-23
  • 2021-08-29
  • 2022-03-08
  • 2022-12-23
  • 2021-12-05
  • 2022-02-28
猜你喜欢
  • 2021-10-14
  • 2021-05-19
  • 2021-06-13
  • 2021-06-21
  • 2022-12-23
  • 2022-12-23
  • 2021-10-06
相关资源
相似解决方案