zoukankan      html  css  js  c++  java
  • [Luogu]P5387 [Cnoi2019]人形演舞(FWT,SG函数)

    刚好FWT和SG函数都刚学,这道题也挺模板的,就拉来做做。
    手动打个SG函数表发现(sg[2^k+n]=n+1),然后博弈论就被干掉了,剩下的问题变成,有(m)个数可以选,选择(v)个数使得异或和为(0)
    这道题题意有锅吧,正确表述应该是大小为(V)的序列,而不是集合,因为方案数跟选取顺序有关。
    (A_k[i])表示选取(k)个数,异或和为(i)的方案数。
    那么(A_{k + 1}[c] = sum_{aoplus b = c} A_k[a] imes A_1[b]),定义乘法为卷积,这样答案就是(A_1^v),快速幂搞一下就行。

    #include <bits/stdc++.h>
    #define int long long
    #define pt(x) cout << x << endl;
    #define Mid ((l + r) / 2)
    #define lson (rt << 1)
    #define rson (rt << 1 | 1)
    using namespace std;
    int read() {
    	char c; int num, f = 1;
    	while(c = getchar(),!isdigit(c)) if(c == '-') f = -1; num = c - '0';
    	while(c = getchar(), isdigit(c)) num = num * 10 + c - '0';
    	return f * num;
    }
    const int N = 2e6 + 1009;
    const int mod = 998244353;
    int n, m, sg[N], A[N], B[N];
    int Pow(int a, int p) {
    	int ans = 1;
    	for( ; p; p >>= 1, a = a * a % mod)
    		if(p & 1)
    			ans = ans * a % mod;
    	return ans % mod;
    }
    void FWT(int *A, int n, int type) {
    	int inv_2 = Pow(2, mod - 2);
    	for(int m = 1; m < n; m <<= 1) {
    		for(int i = 0; i < n; i += 2 * m) {
    			for(int j = 0; j < m; j++) {
    				int x = A[i + j], y = A[i + j + m];
    				A[i + j] = (1ll * x + y) * (type == 1 ? 1 : inv_2) % mod;
    				A[i + j + m] = (1ll * x - y + mod) * (type == 1 ? 1 : inv_2) % mod;
    			}
    		}
    	}
    }
    void Arrtimes(int *A, int lim, int *B) {
    	for(int i = 0; i < lim; i++)
    		A[i] = A[i] * B[i] % mod;
    }
    void FWTPow(int *A, int p, int *B, int lim) {
    	for(int i = 0; i < lim; i++) B[i] = 1;
    	FWT(A, lim, 1);
    	for( ; p; p >>= 1, Arrtimes(A, lim, A))
    		if(p & 1)
    			Arrtimes(B, lim, A);
    	FWT(B, lim, -1);
    }
    signed main()
    {
    	n = read(); m = read();
    	for(int i = 0; i <= m; i++) 
    		sg[i] = i - (1 << (32 - __builtin_clz(i) - 1)) + 1;
    	for(int i = 1; i <= m; i++) A[sg[i]]++;
    	int lim = 1;
    	while(lim <= m) lim <<= 1;
    	FWTPow(A, n, B, lim);
    	printf("%lld
    ", B[0]);
    	
    	printf("%lld
    ", (Pow(m, n) - B[0] + mod) % mod);
    	return 0;
    }
    
    
  • 相关阅读:
    检测单链表是否含有环
    巧用正则和document.location.search获取URL参数的值
    网站前端性能优化
    Ubuntu 10.10 wubi安装错误处理
    SQL中随机数函数rand()简介
    C#实现智能提示(提示补全)功能
    重装系统使之svn再次复活
    MongoDB安装
    mongodb查询
    解决iframe中跨域session丢失的问题
  • 原文地址:https://www.cnblogs.com/onglublog/p/15230104.html
Copyright © 2011-2022 走看看