• @bzoj



    @description@

    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

    @solution@

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

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

    [dp(i, j) = sum_{kin S}dp(i-1, joplus k) ]

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

    这感觉起来像是一个卷积,但是又有点不像我们平常所见的卷积。
    定义 (f(i) = [iin S]),则 (dp(i,j)=sum f(k)*dp(i-1, joplus k))
    好的它就是一个异或卷积。

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

    @accepted code@

    #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
    ", g[0]);
    	}
    }
    

    @details@

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

  • 相关阅读:
    checkbox的checked事件的javascript使用方法
    JSTL标签API(c)的使用
    radios控件的使用
    验证方法判斷input是否为空
    软件课设Day5
    软件课设Day4
    软件课设Day3
    软件课设Day2
    软件课设Day1
    2019/08/23最新进展
  • 原文地址:https://www.cnblogs.com/Tiw-Air-OAO/p/10274039.html
Copyright © 2020-2023  润新知