Hard Nim,HYSBZ - 4589,Nim博弈,FWT

Hard Nim,HYSBZ - 4589

https://vjudge.net/problem/HYSBZ-4589/origin
Claris和NanoApe在玩石子游戏,他们有n堆石子,规则如下:

  1. Claris和NanoApe两个人轮流拿石子,Claris先拿。
  2. 每次只能从一堆中取若干个,可将一堆全取走,但不可不取,拿到最后1颗石子的人获胜。
    不同的初始局面,决定了最终的获胜者,有些局面下先拿的Claris会赢,其余的局面Claris会负。
    Claris很好奇,如果这n堆石子满足每堆石子的初始数量是不超过m的质数,而且他们都会按照最优策略玩游戏,那么NanoApe能获胜的局面有多少种。
    由于答案可能很大,你只需要给出答案对10^9+7取模的值。

思路: 首先很明显是Nim博弈最经典的问题,要使得后手必胜那么所有数的异或值为0,而每个数都是小于等于m的素数,素数筛一遍得到所有素数,即可得到相应的生成函数,用FWT对自己异或卷积n次然后异或值为0的系数即为答案

#include<bits/stdc++.h>
#define MAXN 50005
#define ll long long
using namespace std;
const int MOD = 1e9+7;
int flag[MAXN],prime[MAXN],num;
inline void euler(int n)
{
	for(int i = 2;i <= n;++i)
    {
	    if(!flag[i])
	        prime[++num] = i;
	    for(int j = 1;j <= num && i * prime[j] <= n;++j)
        {
	        flag[i * prime[j]] = 1;
	        if(i % prime[j] == 0)
	            break;
        }
    }
}
inline int qpow(int a,int b,int mod)
{
    int ans = 1;
    while(b)
    {
        if(b & 1) ans = 1ll * ans * a % mod;
        a = 1ll * a * a % mod;
        b >>= 1;
    }
    return ans;
}
int len,inv2;
inline void FWT_xor(int *A,int on)
{
    for(int i=1;i<len;i<<=1) for(int p=i<<1,j=0;j<len;j+=p)
            for(int k=0;k<i;++k)
            {
                int x=A[j+k],y=A[i+j+k];
                A[j+k]=(x+y)%MOD,A[i+j+k]=(x+MOD-y)%MOD;
                if(on==-1) A[j+k]=1ll*A[j+k]*inv2%MOD,A[i+j+k]=1ll*A[i+j+k]*inv2%MOD;//这里是在mol意义下的,否则把inv2改为/2
            }
}
int a[MAXN << 1];
int main()
{
    inv2 = qpow(2,MOD-2,MOD);
    euler(MAXN - 5);
    int n,m;
    while(~scanf("%d%d",&n,&m))
    {
        len = 1;
        while(len <= m) len <<= 1;
        for(int i = 0;i < len;++i) a[i] = 0;
        for(int i = 1;i <= num && prime[i] <= m;++i)
            a[prime[i]] = 1;
        FWT_xor(a,1);
        for(int i = 0;i < len;++i)
            a[i] = qpow(a[i],n,MOD);
        FWT_xor(a,-1);
        printf("%d\n",a[0]);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值