HYSBZ 4589 Hard Nim (FWT)

Claris和NanoApe在玩石子游戲,他們有n堆石子,規則如下:
1. Claris和NanoApe兩個人輪流拿石子,Claris先拿。
2. 每次只能從一堆中取若干個,可將一堆全取走,但不可不取,拿到最後1顆石子的人獲勝。
不同的初始局面,決定了最終的獲勝者,有些局面下先拿的Claris會贏,其餘的局面Claris會負。
Claris很好奇,如果這n堆石子滿足每堆石子的初始數量是不超過m的質數,而且他們都會按照最優策略玩遊戲,那麼NanoApe能獲勝的局面有多少種。
由於答案可能很大,你只需要給出答案對10^9+7取模的值。
Input
輸入文件包含多組數據,以EOF爲結尾。
對於每組數據:
共一行兩個正整數n和m。
每組數據有1<=n<=10^9, 2<=m<=50000。
不超過80組數據。
Output
Sample Input
3 7
4 13
Sample Output
6
120
Hint

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <queue>
#include <set>
#include <map>
#include <algorithm>
#include <math.h>
#include <vector>
using namespace std;
typedef long long ll;

const int mod=1e9+7;
const int maxn=2e5+10;

int n,m;
ll a[maxn],rev;
int prime[maxn],tot;
bool isprime[maxn];
ll Pow(ll a,ll b){
    ll ans=1;
    while (b){
        if (b&1)ans=ans*a%mod;
        b>>=1;
        a=a*a%mod;
    }
    return ans;
}
void init(){
    rev=Pow(2,mod-2);
    tot=0;
    for (int i=2;i<=50000;i++){
        if (!isprime[i]){
            prime[tot++]=i;
        }
        for (int j=i+i;j<=50000;j+=i)isprime[j]=true;
    }

    //for (int i=0;i<15;i++)printf ("%d\n",prime[i]);
} 


//n是2的冪次方 
void FWT(ll a[],int n)
{
    for(int d=1;d<n;d<<=1)
        for(int m=d<<1,i=0;i<n;i+=m)
            for(int j=0;j<d;j++){
                int x=a[i+j],y=a[i+j+d];
                a[i+j]=(x+y)%mod,a[i+j+d]=(x-y+mod)%mod;
                //xor:a[i+j]=x+y,a[i+j+d]=(x-y+mod)%mod;
                //and:a[i+j]=x+y;
                //or:a[i+j+d]=x+y;
            }
}

void UFWT(ll a[],int n)
{
    for(int d=1;d<n;d<<=1)
        for(int m=d<<1,i=0;i<n;i+=m)
            for(int j=0;j<d;j++){
                int x=a[i+j],y=a[i+j+d];
                a[i+j]=1LL*(x+y)*rev%mod,a[i+j+d]=(1LL*(x-y)*rev%mod+mod)%mod;
                //xor:a[i+j]=(x+y)/2,a[i+j+d]=(x-y)/2;
                //and:a[i+j]=x-y;
                //or:a[i+j+d]=y-x;
            }
}
void solve(ll a[],int m,int n)
{
    FWT(a,m);
    for (int i=0;i<m;i++)a[i]=Pow(a[i],n);
    UFWT(a,m);
}
int main()
{   
    init();
    //printf ("%d\n",Pow(2,5));
    while (scanf ("%d%d",&n,&m)!=EOF){
        memset (a,0,sizeof (a));
        int len=1;while (len<=m)len*=2;
        for (int i=0;i<tot&&prime[i]<=m;i++){
            a[prime[i]]++;
        } 
        solve(a,len,n);
        printf ("%lld\n",a[0]);
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章