zoukankan      html  css  js  c++  java
  • bzoj 4589 Hard Nim

    bzoj 4589 Hard Nim

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

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

    [FWT(Aoplus B oplus C)=FWT(IFWT(FWT(A) imes FWT(B))) imes FWT(C)\ =FWT(A) imes FWT(B) imes FWT(C)\ =FWT(A) imes( FWT(B) imes 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;
    }
    
  • 相关阅读:
    【Thymeleaf】利用status对象在th:each语法中显示index
    【Oracle】使用Regexp_like 判断varchar2,nvarchar2型字段里中值是否全由数字组成
    [轉]相機光圈
    選購數碼相機
    [轉載]找不到SQL server ODBC驱动程序的安装例程!请重新安装驱动程序
    [轉]解读GIF文件
    [轉]【经典问题】关于JS验证文本框输入只能输入半角,不让输入全角
    WebGenie
    XML和HTML常用转义字符
    PHP招聘启示
  • 原文地址:https://www.cnblogs.com/jklover/p/10430540.html
Copyright © 2011-2022 走看看