bzoj 4589 Hard Nim——FWT

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

一开始异或和为0的话先手必败。有 n 堆,每堆可以填那些数,求最后异或和为0的方案数,就是一个快速幂的异或FWT。

注意快速幂的过程中对那些数组直接乘就行,不用总是FWT!!!

为什么比Zinn慢了1008ms?

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const int N=5e4+5,mod=1e9+7;
int n,m,pri[5200],cnt,len,inv;
int f[N<<2],a[N<<2],b[N<<2];
bool vis[N];
int pw(int x,int k)
{int ret=1;while(k){if(k&1)ret=(ll)ret*x%mod;x=(ll)x*x%mod;k>>=1;}return ret;}
void fwt(int *a,bool fx)
{
  for(int R=2;R<=len;R<<=1)
    for(int i=0,m=R>>1;i<len;i+=R)
      for(int j=0;j<m;j++)
    {
      int x=a[i+j]+a[i+m+j],y=a[i+j]+mod-a[i+m+j];
      a[i+j]=(ll)x*(fx?inv:1)%mod;
      a[i+m+j]=(ll)y*(fx?inv:1)%mod;
    }
}
void init()
{
  for(int i=2;i<=50000;i++)
    {
      if(!vis[i])pri[++cnt]=i;
      for(int j=1;j<=cnt&&i*pri[j]<=50000;j++)
    {
      vis[i*pri[j]]=1;
      if(i%pri[j]==0)break;
    }
    }
  for(int i=1;i<=cnt;i++)f[pri[i]]=1;
  inv=pw(2,mod-2);
}
int main()
{
  init();
  while(scanf("%d%d",&n,&m)==2)
    {
      for(len=1;len<=m;len<<=1);
      a[0]=1;for(int i=1;i<len;i++)a[i]=0;
      for(int i=0;i<=m;i++)b[i]=f[i];
      for(int i=m+1;i<len;i++)b[i]=0;
      fwt(a,0); fwt(b,0);
      while(n)
    {
      if(n&1)
        for(int i=0;i<len;i++)a[i]=(ll)a[i]*b[i]%mod;
      for(int i=0;i<len;i++)b[i]=(ll)b[i]*b[i]%mod;
      n>>=1;
    }
      fwt(a,1);
      printf("%d\n",a[0]);
    }
  return 0;
}

 

posted on 2018-11-29 18:03  Narh  阅读(212)  评论(0编辑  收藏  举报

导航