• CF1336E1 Chiori and Doll Picking (easy version) [FWT,线性基,折半搜索]


    草,遇到这种时候,上来就应该说一句 Sooke 牛逼!

    考虑这个 (m leq 35) 那么很显然是一个 mid in middle 的范围
    压成线性基,搜两次,算一下高位的 bit数,由于低位不存在高位的bit,拿来和后边存在高位的bit卷一下就可以了。
    我们把 (>=17) 的位拿来 (FWT),然后卷积,没了。
    需要注意的是,加入一共有 (n) 个数字,线性基里面有 (k) 个数字,那么线性基的每个能构造出来的数字数量是 (2^{n-k})
    所以答案应该乘上一个 (2^{n-k})

    #include<bits/stdc++.h>
    #define int long long
    using namespace std;
    const int mod = 998244353;
    const int maxn = 4e5 + 54;
    int n, m;
    int a[maxn];
    int f[28][maxn], g[maxn];
    int d[2333], c = 0;
    int cnt[maxn << 1];
    int ans[maxn], tmp[maxn];
    void ins(int x) {
    	for(int i = m - 1 ; ~ i ; i --) {
    		if(x & (1ll << i)) {
    			if(! d[i]) {
    				d[i] = x;
    				++ c;
    			}
    			x ^= d[i];
    		}
    	}
    }
    
    int mid;
    void dfs(int u, int num) {
    	if(u == mid - 1) {
    		f[cnt[num >> mid]][num & ((1 << mid) - 1)] ++;
    		return;
    	}
    	dfs(u - 1, num);
    	if(d[u]) {
    		dfs(u - 1, num ^ d[u]);
    	}
    }
    
    void dfs2(int u, int num) {
    	if(u == mid) {
    		g[num] ++;
    		return ;
    	}
    	dfs2(u + 1, num);
    	if(d[u]) {
    		dfs2(u + 1, num ^ d[u]);
    	}
    }
    
    int qpow(int x,int y) {
    	int ans = 1;
    	for(; y; y >>= 1, x = x * x % mod)
    		if(y & 1)
    			ans = ans * x % mod;
    	return ans;
    }
    
    const int inv2 = qpow(2, mod - 2);
    
    void fwt(int *f, int type, int n) {
    	for(int len = 1 ; len < n ; len <<= 1) {
    		for(int i = 0 ; i < n ; i += len << 1) {
    			for(int j = 0; j < len ; j ++) {
    				int x = f[i + j];
    				int y = f[i + j + len];
    				f[i + j] = (x + y) % mod;
    				f[i + j + len] = (x - y + mod) % mod;
    				if(type == -1)
    					f[i + j] = f[i + j] * inv2 % mod,
    					f[i + j + len] = f[i + j + len] * inv2 % mod;
    			}
    		}
    	}
    }
    
    signed main() {
    	ios :: sync_with_stdio(false);
    	cin.tie(nullptr);
    	cout.tie(nullptr);
    	cin >> n >> m;
    	for(int i = 1 ; i <= n ; i ++) 
    		cin >> a[i];
    	for(int i = 1 ; i <= n ; i ++)
    		ins(a[i]);
    	mid = m + 1 >> 1;
    	for(int i = 1 ; i <= 300000 ; i ++)
    		cnt[i] = cnt[i >> 1] + (i & 1);
    	dfs(m - 1, 0);
    	dfs2(0, 0);
    	memcpy(tmp, g, sizeof(g));
    	for(int i = 0; i <= m - mid ; i ++) {
    		memcpy(g, tmp, sizeof(g));
    		fwt(f[i], 1, 1 << mid);
    		fwt(g, 1, 1 << mid);
    		for(int j = 0; j < (1 << mid); ++j)
    			f[i][j] = f[i][j] * g[j] % mod;
    		fwt(f[i], -1, 1 << mid);
    		for(int j = 0; j < (1 << mid); ++j)
    			ans[i + cnt[j]] = (ans[i + cnt[j]] + f[i][j]) % mod;
    	}
    	int qwq = qpow(2, n - c) ;
    	for(int i = 0 ; i <= m ; i++)
    		ans[i] = ans[i] * qwq % mod;
    	for(int i = 0 ; i <= m ; i ++)
    		cout << ans[i] << ' ';
    	cout << '
    ';
    	return 0;
    } 
    
  • 相关阅读:
    源代码搭建应用(一)——动手搭建自己的计算集群系统
    [转载]Ubuntu 14.04中root 密码忘记解决方法
    如何用路由器改成WiFi Pineapple系统镜像网络流量
    DELPHI黑客编程(一):正向后门原理实现
    OpenWrt 路由器过滤广告的N种方法
    Windows 10 上强制Visual Studio以管理员身份运行
    DB2修改表字段
    Git Fast-forward提交
    C#(去、过滤)掉字符中的换行符
    VS读取文件或写入文件时出现中文乱码问题
  • 原文地址:https://www.cnblogs.com/Isaunoya/p/12818995.html
Copyright © 2020-2023  润新知