BZOJ-4589: Hard Nim

[文章目录]

Description

n堆石子,每堆个数为不超过m的质数。询问玩Nim游戏先手必输的方案数。多组询问,T<=80 n<=10^9 m<=5*10^4

设dp[i]表示亦或和为i的方案数,转移
FWT优化位运算亦或卷积,初始化一堆时的dp值,求出F'[i]=(-1)^count(j&i)*f[j]后快速幂即可。时间复杂度O(mlogm+mlogn)

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define M 51000 
const int mod=1000000007;
typedef long long ll;
int n,m,lim;
int pri[M],cnt,a[101000];
bool v[M<<1];
void initialize()
{
    int i,j;
    for(i=2;i<=100000;++i)
    {
        if(!v[i]) pri[++cnt]=i;
        for(j=1;i*pri[j]<=100000&&j<=cnt;++j)
        {
            v[i*pri[j]]=1;
            if(i%pri[j]==0) break;
        }
    }
}
void fwt(int len)
{
    int i,j,k;
    for(i=1;i<len;i<<=1)
        for(j=0;j<len;j+=(i<<1))
            for(k=j;k<j+i;++k)
                a[k]=a[k]+a[k+i],a[k+i]=a[k]-(a[k+i]<<1);
}
void ufwt(int len)
{
    int i,j,k;
    for(i=len>>1;i;i>>=1)
        for(j=0;j<len;j+=(i<<1))
            for(k=j;k<j+i;++k)
                a[k]=(500000004ll*(a[k]+a[k+i]))%mod,a[k+i]=(a[k]-a[k+i]+mod)%mod;
}
int Pow(ll x,int y)
{
    ll re=1; x=(x%mod+mod)%mod;
    while(y)
    {
        if(y&1) re=re*x%mod;
        x=x*x%mod; y>>=1;
    }
    return re;
}
int main()
{
    initialize();
    while(~scanf("%d%d",&n,&m))
    {
        memset(a,0,sizeof a);
        for(int i=1;pri[i]<=m;++i) a[pri[i]]=1;
        for(lim=1;lim<=m;lim<<=1);
        fwt(lim);
        for(int i=0;i<lim;++i) a[i]=Pow(a[i],n);
        ufwt(lim);
        printf("%d\n",(a[0]%mod+mod)%mod);
    }
    return 0;
}

发表评论

邮箱地址不会被公开。 必填项已用*标注