[BZOJ4589]Hard Nim

description

BZOJ
题意:\(n\)堆式子,每堆石子数量为\(\le m\)的质数,对于每一个局面玩\(Nim\)游戏,求后手必胜的方案数。

data range

\[n\le 10^9,m\le 5\times 10^4 \]

solution

直接\(FWT\)多项式快速幂即可。

之前写的多项式快速幂一直是\(O(mlogmlogn)\)
然后在这一道题上\(T\)了...

\(\%\)了一发\(yyb\)的代码才知道原来可以快速幂的时候可以不用每次\(FWT\)
这样就变成\(O(m(logm+logn))\)的了

orz 神仙yyb

Code

#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<iomanip>
#include<cstring>
#include<complex>
#include<vector>
#include<cstdio>
#include<string>
#include<bitset>
#include<ctime>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#define Cpy(x,y) memcpy(x,y,sizeof(x))
#define Set(x,y) memset(x,y,sizeof(x))
#define FILE "a"
#define mp make_pair
#define pb push_back
#define RG register
#define il inline
using namespace std;
typedef unsigned long long ull;
typedef vector<int>VI;
typedef long long ll;
typedef double dd;
const int N=1<<16;
const int M=1e5+10;
const int mod=1e9+7;
const int base=26;
const dd eps=1e-6;
const int inf=2147483647;
const ll INF=1ll<<60;
const ll P=100000;
il ll read(){
  RG ll data=0,w=1;RG char ch=getchar();
  while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
  if(ch=='-')w=-1,ch=getchar();
  while(ch<='9'&&ch>='0')data=data*10+ch-48,ch=getchar();
  return data*w;
}

il void file(){
  srand(time(NULL)+rand());
  freopen(FILE".in","r",stdin);
  freopen(FILE".out","w",stdout);
}

int pri[N];bool vis[N];
il void upd(int &a,int b){a+=b;if(a>=mod)a-=mod;}
il void dec(int &a,int b){if(b)upd(a,mod-b);}
il void sieve(){
  vis[1]=1;
  for(RG int i=2;i<N;i++){
    if(!vis[i])pri[++pri[0]]=i;
    for(RG int j=1;j<=pri[0]&&1ll*i*pri[j]<N;j++){
      vis[i*pri[j]]=1;if(i%pri[j]==0)break;
    }
  }
}
il void FWT_xor(int *a,int n,int opt){
  for(RG int i=1,x,y,inv2=(mod+1)/2;i<n;i<<=1)
    for(RG int j=0,p=i<<1;j<n;j+=p)
      for(RG int k=0;k<i;k++){
	x=a[j+k];y=a[i+j+k];a[i+j+k]=x;
	upd(a[j+k],y);dec(a[i+j+k],y);
	if(opt==-1)a[j+k]=1ll*a[j+k]*inv2%mod,a[i+j+k]=1ll*a[i+j+k]*inv2%mod;
      }
}
int f[N],g[N];

int main()
{
  sieve();RG int n,m;
  while(scanf("%d%d",&n,&m)!=EOF){
    memset(f,0,sizeof(f));memset(g,0,sizeof(g));f[0]=1;
    for(RG int i=1;pri[i]<=m&&i<=pri[0];i++)g[pri[i]]=1;
    FWT_xor(f,N,1);FWT_xor(g,N,1);
    while(n){
      if(n&1)for(RG int i=0;i<N;i++)f[i]=1ll*f[i]*g[i]%mod;
      for(RG int i=0;i<N;i++)g[i]=1ll*g[i]*g[i]%mod;
      n>>=1;
    }
    FWT_xor(f,N,-1);
    printf("%d\n",f[0]);
  }
  return 0;
}

posted @ 2018-10-01 22:12  cjfdf  阅读(160)  评论(0编辑  收藏