[bzoj4589]Hard Nim——SG函数+FWT

题目大意:

Claris和NanoApe在玩石子游戏,他们有n堆石子,规则如下:

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

    思路:

    先手必败是所有的石子的SG函数值异或起来等于0。
    设\(f_{i,j}\)表示进行了第\(i\)堆石子,异或和为\(j\)的方案数是多少,实际上是一个异或卷积,直接上FWT优化即可。

/*=======================================
 * Author : ylsoi
 * Time : 2010.2.10
 * Problem : bzoj4589
 * E-mail : [email protected]
 * ====================================*/
#include<bits/stdc++.h>

#define REP(i,a,b) for(int i=a,i##_end_=b;i<=i##_end_;++i)
#define DREP(i,a,b) for(int i=a,i##_end_=b;i>=i##_end_;--i)
#define debug(x) cout<<#x<<"="<<x<<" "
#define fi first
#define se second
#define mk make_pair
#define pb push_back
typedef long long ll;

using namespace std;

void File(){
    freopen("bzoj4589.in","r",stdin);
    freopen("bzoj4589.out","w",stdout);
}

template<typename T>void read(T &_){
    _=0; T f=1; char c=getchar();
    for(;!isdigit(c);c=getchar())if(c=='-')f=-1;
    for(;isdigit(c);c=getchar())_=(_<<1)+(_<<3)+(c^'0');
    _*=f;
}

const int maxn=5e4+10;
const ll mod=1e9+7;
const ll inv2=(mod+1)/2;
int n,m,lim;
ll f[maxn<<1];
int pm[maxn],tot;
bool vis[maxn];

void init_prime(){
    REP(i,2,5e4){
        if(!vis[i])pm[++tot]=i;
        REP(j,1,tot){
            if(i*pm[j]>5e4)break;
            vis[i*pm[j]]=1;
            if(i%pm[j]==0)break;
        }
    }
}

ll qpow(ll x,ll y){
    ll ret=1; x%=mod;
    while(y){
        if(y&1)ret=ret*x%mod;
        x=x*x%mod;
        y>>=1;
    }
    return ret;
}

void fwt(ll *A,int ty){
    for(int len=1;len<lim;len<<=1)
        for(int L=0;L<lim;L+=len<<1)
            REP(i,L,L+len-1){
                ll x=A[i],y=A[i+len];
                A[i]=(x+y)*(ty==1 ? 1 : inv2)%mod;
                A[i+len]=(x-y)*(ty==1 ? 1 : inv2)%mod;
            }
}

int main(){
    File();
    init_prime();
    while(~scanf("%d%d",&n,&m)){
        lim=1;
        while(lim<=m)lim<<=1;
        REP(i,0,lim-1)f[i]=0;
        REP(i,1,tot)if(pm[i]<=m)f[pm[i]]=1;
        else break;
        fwt(f,1);
        REP(i,0,lim-1)f[i]=qpow(f[i],n);
        fwt(f,-1);
        printf("%lld\n",(f[0]+mod)%mod);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/ylsoi/p/10359568.html

时间: 2024-11-04 08:27:32

[bzoj4589]Hard Nim——SG函数+FWT的相关文章

HDU 3032 Nim or not Nim?(sg函数)

题目链接 暴力出来,竟然眼花了以为sg(i) = i啊....看表要认真啊!!! #include <cstdio> #include <cstring> #include <iostream> using namespace std; #define LL __int64 int dp[10001]; int sg(int x) { int flag[10001],temp,i; if(dp[x] >= 0) return dp[x]; memset(flag,

hdu 3032 Nim or not Nim? sg函数

Nim or not Nim? Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 1056    Accepted Submission(s): 523 Problem Description Nim is a two-player mathematic game of strategy in which players take turn

HDU 3032 Nim or not Nim?(sg函数博弈)

题目地址:HDU 3032 这题是很好用来练习sg函数打表的一题. 下面是sg函数值打表代码: #include <iostream> #include <cstdio> #include <string> #include <cstring> #include <stdlib.h> #include <math.h> #include <ctype.h> #include <queue> #include &

HDU 1729 Stone Game 石头游戏 (Nim, sg函数)

题意:有n个盒子,每个盒子可以放一定量的石头,盒子中可能已经有了部分石头.假设石头无限,每次可以往任意一个盒子中放石头,可以加的数量不得超过该盒中已有石头数量的平方k^2,即至少放1个,至多放k^2个. 思路:跟常规nim的区别就是加了个限制“每次加的量不超平方”.盒子容量上限是100万,那么就不能直接计算SG了,会超时.sg打表后找规律.根据剩下多少个空位来决定sg值.都是0123456这样子递增的,碰到不能一次加满就变为0,然后继续递增,一直这样. 我的方案是,对于每个盒子大小,找到除了自己

HDU 3032-Nim or not Nim?(sg函数打表)

Nim or not Nim? Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 1099    Accepted Submission(s): 547 Problem Description Nim is a two-player mathematic game of strategy in which players take tur

Nim 游戏、SG 函数、游戏的和

Nim游戏 Nim游戏定义 Nim游戏是组合游戏(Combinatorial Games)的一种,准确来说,属于"Impartial Combinatorial Games"(以下简称ICG).满足以下条件的游戏是ICG(可能不太严谨):1.有两名选手:2.两名选手交替对游戏进行移动(move),每次一步,选手可以在(一般而言)有限的合法移动集合中任选一种进行移动:3.对于游戏的任何一种可能的局面,合法的移动集合只取决于这个局面本身,不取决于轮到哪名选手操作.以前的任何操作.骰子的点数

HDU 5795 A Simple Nim 打表求SG函数的规律

A Simple Nim Problem Description Two players take turns picking candies from n heaps,the player who picks the last one will win the game.On each turn they can pick any number of candies which come from the same heap(picking no candy is not allowed).T

HDU 3032 Nim or not Nim? (sg函数求解)

Nim or not Nim? Problem Description Nim is a two-player mathematic game of strategy in which players take turns removing objects from distinct heaps. On each turn, a player must remove at least one object, and may remove any number of objects provide

HDU 3032 Nim or not Nim? (博弈之求SG函数)

题意:经典Nim博弈游戏变换,给你n堆石子pi,每堆有pi个石子, Alice和Bob轮流取石子,每次可以从任意一堆中拿走任意个石子,也可以将某一堆石子分成两个小堆 (每堆石子个数必须不能为0),先拿完者获胜 思路:求SG函数后找规律: SG函数定义及求法:点击打开链接 #include<cstdio> #include<stdlib.h> #include<string.h> #include<string> #include<map> #in