@bzoj - [email protected] Hard Nim

目录

  • @[email protected]
  • @[email protected]
  • @accepted [email protected]
  • @[email protected]

@[email protected]

n 堆石子,每堆石子的数量是不超过 m 的一个质数。

两个人玩 nim 游戏,问使后手必胜的初始局面有多少种。

模 10^9 + 7。

input

多组数据。数据组数 <= 80。

每组数据一行两个正整数,n 和 m。1 <= n <= 10^9, 2 <= m <= 50000。

output

对于每组数据,输出一行答案。

sample input

3 7

4 13

sample output

6

120

@[email protected]

根据常识,异或起来等于 0,nim 游戏就一定后手必胜。

定义 dp(i, j) 前 i 堆石子异或起来等于 j 的方案数,则有转移:

\[dp(i, j) = \sum_{k\in S}dp(i-1, j\oplus k)\]

其中 S 是小于等于 m 的质数集合,初始情况 dp(0, 0) = 1。

这感觉起来像是一个卷积,但是又有点不像我们平常所见的卷积。

定义 \(f(i) = [i\in S]\),则 \(dp(i,j)=\sum f(k)*dp(i-1, j\oplus k)\)。

好的它就是一个异或卷积。

我们的 dp(n)其实就是 f^n。因此,我们只需要先对 f 进行 FWT 正变换,再对每一个数进行快速幂,最后再 FWT 逆变换回来,f(0) 就是我们的答案。

@accepted [email protected]

#include<cstdio>
const int MAXN = 100000;
const int MOD = int(1E9) + 7;
const int INV = (MOD + 1) >> 1;
int pow_mod(int b, int p) {
    int ret = 1;
    while( p ) {
        if( p & 1 ) ret = 1LL*ret*b%MOD;
        b = 1LL*b*b%MOD;
        p >>= 1;
    }
    return ret;
}
int f[MAXN + 5], prm[MAXN + 5], pcnt = 0;
bool isprm[MAXN + 5];
void init() {
    for(int i=2;i<=MAXN;i++) {
        if( !isprm[i] ) {
            prm[++pcnt] = i;
            f[i] = 1;
        }
        for(int j=1;1LL*i*prm[j]<=MAXN;j++) {
            isprm[i*prm[j]] = true;
            if( i % prm[j] == 0 )
                break;
        }
    }
}
void fwt(int *a, int n, int type) {
    for(int s=2;s<=n;s<<=1) {
        for(int i=0,t=(s>>1);i<n;i+=s) {
            for(int j=0;j<t;j++) {
                int x = a[i+j], y = a[i+j+t];
                a[i+j] = 1LL*(x + y)%MOD*(type == 1 ? 1 : INV)%MOD;
                a[i+j+t] = 1LL*(x + MOD - y)%MOD*(type == 1 ? 1 : INV)%MOD;
            }
        }
    }
}
int g[MAXN + 5];
int main() {
    init(); int n, m;
    while( scanf("%d%d", &n, &m) == 2 ) {
        int len = 1; while( len <= m ) len <<= 1;
        for(int i=0;i<len;i++)
            g[i] = 0;
        for(int i=1;i<=m;i++)
            g[i] = f[i];
        fwt(g, len, 1);
        for(int i=0;i<len;i++)
            g[i] = pow_mod(g[i], n);
        fwt(g, len, -1);
        printf("%d\n", g[0]);
    }
}

@[email protected]

我才不会说我因为初始化只把m以内的数清零然后WA好几遍呢。

原文地址:https://www.cnblogs.com/Tiw-Air-OAO/p/10274039.html

时间: 2024-08-28 04:19:33

@bzoj - [email protected] Hard Nim的相关文章

@bzoj - [email&#160;protected] [POI2015] Kinoman

目录 @[email protected] @[email protected] @accepted [email protected] @[email protected] @[email protected] 共有 m 部电影,第 i 部电影的好看值为 w[i]. 在 n 天之中每天会放映一部电影,第 i 天放映的是第 f[i] 部. 你可以选择 l, r (1 <= l <= r <= n) ,并观看第 l, l+1, -, r 天内所有的电影. 最大化观看且仅观看过一次的电影的好

@bzoj - [email&#160;protected] [Poi2011]Lightning Conductor

目录 @[email protected] @[email protected] @part - [email protected] @part - [email protected] @part - [email protected] @accepted [email protected] @version - [email protected] @version - [email protected] @[email protected] @[email protected] 已知一个长度为

@bzoj - [email&#160;protected] [POI2014]Hotel加强版

目录 @[email protected] @[email protected] @part - [email protected] @part - [email protected] @accepted [email protected] @[email protected] @[email protected] 给定一棵树,求无序三元组 (a, b, c) 的个数,使得 dis(a, b) = dis(b, c) = dis(c, a),且 a ≠ b, b ≠ c, c ≠ a. inpu

@bzoj - [email&#160;protected] 旅行规划

目录 @[email protected] @[email protected] @accepted [email protected] @[email protected] @[email protected] 请你维护一个序列,支持两种操作: (1)某个区间 [x, y] 内的数同时加上一个增量 k. (2)询问某一个区间 [x, y] 中从 1 开始的最大前缀和. input 第一行给出一个整数 n.n <= 100000.接下来一行 n 个整数表示序列的初始值. 第三行给出一个整数 m,

@bzoj - [email&#160;protected] [Cqoi2016]伪光滑数

目录 @description@ @[email protected] @version - [email protected] @version - [email protected] @accepted [email protected] @[email protected] @description@ 若一个大于 1 的整数 M 的质因数分解有 k 项,其最大的质因子为 \(A_k\),并且满足 \(A_k^k \le N\),\(A_k < 128\),我们就称整数 M 为 N - 伪光

@bzoj - [email&#160;protected] [POI2015] Wilcze do?y

目录 @[email protected] @[email protected] @accepted [email protected] @[email protected] @[email protected] 给定一个长度为 n 的序列,你有一次机会选中一段连续的长度不超过 d 的区间,将里面所有数字全部修改为 0. 请找到最长的一段连续区间,使得该区间内所有数字之和不超过 p . input 第一行包含三个整数 n, p, d (1 <= d <= n <= 2000000,0 &

@bzoj - [email&#160;protected] [POI2015] Pustynia

目录 @[email protected] @[email protected] @accepted [email protected] @[email protected] @[email protected] 给定一个长度为 n 的正整数序列 a,每个数都在 1 到 10^9 范围内. 告诉你其中 s 个数,并给出 m 条信息,每条信息包含三个数 l, r, k 以及 k 个正整数,表示 a[l], a[l+1], ..., a[r-1], a[r] 里这 k 个数中的任意一个都比任意一个剩

@bzoj - [email&#160;protected] [POI2015] Logistyka

目录 @[email protected] @[email protected] @accepted [email protected] @[email protected] @[email protected] 维护一个长度为 n 的序列,一开始都是 0,支持以下两种操作: 1.U k a 将序列中第 k 个数修改为 a. 2.Z c s 在这个序列上,每次选出 c 个正数,并将它们都减去 1,询问能否进行 s 次操作. 每次询问独立,即每次询问不会对序列进行修改. input 第一行包含两个

@bzoj - [email&#160;protected] [POI2015] Myjnie

目录 @[email protected] @[email protected] @accepted [email protected] @[email protected] @[email protected] 有 n 家洗车店从左往右排成一排,每家店都有一个正整数价格 p[i]. 有 m 个人要来消费,第 i 个人会驶过第 a[i] 个开始一直到第 b[i] 个洗车店,且会选择这些店中最便宜的一个进行一次消费.但是如果这个最便宜的价格大于 c[i],那么这个人就不洗车了. 请给每家店指定一个