BZOJ 4589: Hard Nim DP+快速幂+FWT
朴素的DP:$f[i][j]$ 表示选了 $i$ 个数,异或值为 $j$ 的方案数.
转移:$f[i][j]=\sum_{i=1}^{m}f[i-1][k]\times isprime[p]$($p$ 异或 $k$ 等于 $j$)
如果 $n$ 比较小的话可以直接进行 FWT 优化 DP.
然而,这道题中 $n=10^9$,那就用快速幂优化 DP 就好啦 ~
code:
#include <cstdio> #include <algorithm> #define ll long long #define N 100002 #define MAXM 50000 #define mod 1000000007 #define setIO(s) freopen(s".in","r",stdin) // ,freopen(s".out","w",stdout) using namespace std; int lim,inv,tot; int ar[N],br[N],prime[MAXM],vis[MAXM]; int qpow(int x,int y) { int tmp=1; for(;y;y>>=1,x=(ll)x*x%mod) if(y&1) tmp=(ll)tmp*x%mod; return tmp; } void FWT(int *f,int opt) { int i,j,k; for(i=1;i<lim;i<<=1) { for(j=0;j<lim;j+=i<<1) for(k=0;k<i;++k) { int x=f[j+k],y=f[j+k+i]; f[j+k]=(ll)(x+y)%mod; f[j+k+i]=(ll)(x-y+mod)%mod; if(opt==-1) { f[j+k]=1ll*inv*f[j+k]%mod; f[j+k+i]=1ll*inv*f[j+k+i]%mod; } } } } void init() { int i,j; for(i=2;i<MAXM;++i) { if(!vis[i]) prime[++tot]=i; for(j=1;j<=tot&&prime[j]*i<MAXM;++j) { vis[i*prime[j]]=1; if(i%prime[j]==0) break; } } } void DP(int y) { for(int i=0;i<lim;++i) br[i]=ar[i]; while(y) { if(y&1) { for(int i=0;i<lim;++i) ar[i]=(ll)ar[i]*br[i]%mod; } y>>=1; for(int i=0;i<lim;++i) { br[i]=(ll)br[i]*br[i]%mod; } } } int main() { // setIO("input"); int i,j,n,m; inv=qpow(2,mod-2),init(); while(scanf("%d%d",&n,&m)!=EOF) { for(i=1;i<=tot&&prime[i]<=m;++i) ar[prime[i]]=1; for(lim=1;lim<=m;lim<<=1); FWT(ar,1); DP(n-1); FWT(ar,-1); printf("%d\n",ar[0]); for(i=0;i<lim;++i) ar[i]=br[i]=0; } return 0; }