zoukankan      html  css  js  c++  java
  • [bzoj4589]Hard Nim——SG函数+FWT

    题目大意:

    Claris和NanoApe在玩石子游戏,他们有n堆石子,规则如下:

    1. Claris和NanoApe两个人轮流拿石子,Claris先拿。
    2. 每次只能从一堆中取若干个,可将一堆全取走,但不可不取,拿到最后1颗石子的人获胜。
      不同的初始局面,决定了最终的获胜者,有些局面下先拿的Claris会赢,其余的局面Claris会负。
      Claris很好奇,如果这n堆石子满足每堆石子的初始数量是不超过m的质数,而且他们都会按照最优策略玩游戏,那么NanoApe能获胜的局面有多少种。
      由于答案可能很大,你只需要给出答案对10^9+7取模的值。

    思路:

    先手必败是所有的石子的SG函数值异或起来等于0。
    (f_{i,j})表示进行了第(i)堆石子,异或和为(j)的方案数是多少,实际上是一个异或卷积,直接上FWT优化即可。

    /*=======================================
     * Author : ylsoi
     * Time : 2010.2.10
     * Problem : bzoj4589
     * E-mail : ylsoi@foxmail.com
     * ====================================*/
    #include<bits/stdc++.h>
    
    #define REP(i,a,b) for(int i=a,i##_end_=b;i<=i##_end_;++i)
    #define DREP(i,a,b) for(int i=a,i##_end_=b;i>=i##_end_;--i)
    #define debug(x) cout<<#x<<"="<<x<<" "
    #define fi first
    #define se second
    #define mk make_pair
    #define pb push_back
    typedef long long ll;
    
    using namespace std;
    
    void File(){
    	freopen("bzoj4589.in","r",stdin);
    	freopen("bzoj4589.out","w",stdout);
    }
    
    template<typename T>void read(T &_){
    	_=0; T f=1; char c=getchar();
    	for(;!isdigit(c);c=getchar())if(c=='-')f=-1;
    	for(;isdigit(c);c=getchar())_=(_<<1)+(_<<3)+(c^'0');
    	_*=f;
    }
    
    const int maxn=5e4+10;
    const ll mod=1e9+7;
    const ll inv2=(mod+1)/2;
    int n,m,lim;
    ll f[maxn<<1];
    int pm[maxn],tot;
    bool vis[maxn];
    
    void init_prime(){
    	REP(i,2,5e4){
    		if(!vis[i])pm[++tot]=i;
    		REP(j,1,tot){
    			if(i*pm[j]>5e4)break;
    			vis[i*pm[j]]=1;
    			if(i%pm[j]==0)break;
    		}
    	}
    }
    
    ll qpow(ll x,ll y){
    	ll ret=1; x%=mod;
    	while(y){
    		if(y&1)ret=ret*x%mod;
    		x=x*x%mod;
    		y>>=1;
    	}
    	return ret;
    }
    
    void fwt(ll *A,int ty){
    	for(int len=1;len<lim;len<<=1)
    		for(int L=0;L<lim;L+=len<<1)
    			REP(i,L,L+len-1){
    				ll x=A[i],y=A[i+len];
    				A[i]=(x+y)*(ty==1 ? 1 : inv2)%mod;
    				A[i+len]=(x-y)*(ty==1 ? 1 : inv2)%mod;
    			}
    }
    
    int main(){
    	File();
    	init_prime();
    	while(~scanf("%d%d",&n,&m)){
    		lim=1;
    		while(lim<=m)lim<<=1;
    		REP(i,0,lim-1)f[i]=0;
    		REP(i,1,tot)if(pm[i]<=m)f[pm[i]]=1;
    		else break;
    		fwt(f,1);
    		REP(i,0,lim-1)f[i]=qpow(f[i],n);
    		fwt(f,-1);
    		printf("%lld
    ",(f[0]+mod)%mod);
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    信息安全
    软件体系结构原理、方法与实践总结
    软件项目管理四个核心价值观
    博客园主题修改
    测试
    Java实现人民币大写精讲
    Windows系统性能提升方法
    Oracle系列之游标
    Oracle系列之异常处理
    Oracle系列之权限
  • 原文地址:https://www.cnblogs.com/ylsoi/p/10359568.html
Copyright © 2011-2022 走看看