[bzoj4589]Hard Nim——SG函數+FWT
阿新 • • 發佈:2019-02-10
fir 直接 scan 異或和 sdi n-1 ons 個人 sg函數
題目大意:
Claris和NanoApe在玩石子遊戲,他們有n堆石子,規則如下:
- Claris和NanoApe兩個人輪流拿石子,Claris先拿。
每次只能從一堆中取若幹個,可將一堆全取走,但不可不取,拿到最後1顆石子的人獲勝。
不同的初始局面,決定了最終的獲勝者,有些局面下先拿的Claris會贏,其余的局面Claris會負。
Claris很好奇,如果這n堆石子滿足每堆石子的初始數量是不超過m的質數,而且他們都會按照最優策略玩遊戲,那麽NanoApe能獲勝的局面有多少種。
由於答案可能很大,你只需要給出答案對10^9+7取模的值。思路:
先手必敗是所有的石子的SG函數值異或起來等於0。
設\(f_{i,j}\)
/*======================================= * 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