1. 程式人生 > >[bzoj4589]Hard Nim——SG函數+FWT

[bzoj4589]Hard Nim——SG函數+FWT

fir 直接 scan 異或和 sdi n-1 ons 個人 sg函數

題目大意:

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 : [email protected]
 * ====================================*/
#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\n",(f[0]+mod)%mod);
    }
    return 0;
}

[bzoj4589]Hard Nim——SG函數+FWT