1. 程式人生 > >bzoj 4589 Hard Nim —— FWT

bzoj 4589 Hard Nim —— FWT

https ont www. 需要 col ace == 每次 geo

題目:https://www.lydsy.com/JudgeOnline/problem.php?id=4589

先手必敗,是一開始所有石子的異或和為0;

生成函數 (xpri[1] + xpri[2] + ... + xpri[k])n,pri[k] <= m

FWT求解即可;

而且不要快速冪裏面每次變換來變換去的,只有快速冪前後需要變換。

代碼如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef 
long long ll; int const xn=(1<<16),mod=1e9+7; int n,m,a[xn],b[xn],lim,inv,cnt,pri[xn]; bool vis[xn]; void init() { int mx=xn-1; for(int i=2;i<=mx;i++) { if(!vis[i])pri[++cnt]=i; for(int j=1;j<=cnt&&(ll)i*pri[j]<=mx;j++) { vis[i*pri[j]]=1; if
(i%pri[j]==0)break; } } } int upt(int x){while(x>=mod)x-=mod; while(x<0)x+=mod; return x;} ll pw(ll a,int b) { ll ret=1; for(;b;b>>=1,a=(a*a)%mod)if(b&1)ret=(ret*a)%mod; return ret; } void fwt(int *a,int tp) { for(int mid=1;mid<lim;mid<<=1) for(int j=0,len=(mid<<1
);j<lim;j+=len) for(int k=0;k<mid;k++) { int x=a[j+k],y=a[j+mid+k]; a[j+k]=upt(x+y); a[j+mid+k]=upt(x-y); if(tp==-1)a[j+k]=(ll)a[j+k]*inv%mod,a[j+mid+k]=(ll)a[j+mid+k]*inv%mod; } } int main() { inv=pw(2,mod-2); init(); while(scanf("%d%d",&n,&m)==2) { memset(a,0,sizeof a); for(int i=2;i<=m;i++)if(!vis[i])a[i]=1; memset(b,0,sizeof b); b[0]=1; lim=1; while(lim<=m)lim<<=1; fwt(a,1); fwt(b,1); for(;n;n>>=1) { if(n&1)for(int i=0;i<lim;i++)b[i]=(ll)a[i]*b[i]%mod; for(int i=0;i<lim;i++)a[i]=(ll)a[i]*a[i]%mod; } fwt(b,-1); printf("%d\n",b[0]); } return 0; }

bzoj 4589 Hard Nim —— FWT