• icpc2020沈阳 M (fwt+高维前缀和)


    题目链接:https://codeforces.com/gym/103202/problem/M

    一句话题意:求满足 $$sumlimits_{i=1}^n sumlimits_{j=i+1}^{n}[a_i oplus a_j cap S>0] >= k$$ 的集合 (S) 的数量

    将问题分为两部分,第一步,求出 $$sumlimits_{i=1}^{n} sumlimits_{j=i+1}^{n} a_i oplus a_j = S$$ 的 ((i,j))对的数量
    (num[i]) 表示 (i) 的数量,答案即为 (F[s] = frac{1}{2}sumlimits_{ioplus j = S}num[i]*num[j])(fwt) 即可

    第二步,如果 (G[S] = sumlimits_{Tcap S eq 0} F[T] >= k),则 (S) 有贡献,容斥一下变为 (G[S] = frac{n imes n}{2} - sumlimits_{Tcap S = 0} F[T]),即求 (S) 补集的子集和,高维前缀和可在 (O(m2^m)) 内求出

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    const int maxn = 200010;
    const int maxm = (1 << 20) + 10;
    
    int n, m, N; ll k;
    ll a[maxm], b[maxm], g[maxn];
    
    void fwt(ll *f,int type){
    	for(int i=1;i<N;i<<=1){
    		for(int j=0;j<N;j+=(i<<1)){
    			for(int k=0;k<i;k++){
    				ll p=f[j+k],q=f[i+j+k];
    				if(type==1) f[j+k]=p+q,f[i+j+k]=p-q;
    				else f[j+k]=(p+q)/2,f[i+j+k]=(p-q)/2;
    			}
    		}
    	}
    }
    
    char s[maxn];
    
    ll read(){ ll s = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar(); } while(ch >= '0' && ch <= '9'){ s = s * 10 + ch - '0'; ch = getchar(); } return s * f; }
    
    int main(){
    	scanf("%d%d%lld", &n, &m, &k);
    	N = (1 << m);
    	
    	int num = 0;
    	for(int i = 1 ; i <= n ; ++i){
    		scanf("%s", s+1);
    		int len = strlen(s+1);
    		num = 0;
    		for(int j = 1 ; j <= len ; ++j){
    			num = (num<<1) + (s[j] == 'A' ? 1 : 0);
    		}
    		++a[num];
    	}
    	for(int i = 0 ; i < N ; ++i) b[i] = a[i];
    	
    	fwt(a, 1), fwt(b, 1);
    	for(int i = 0 ; i < N ; ++i) a[i] = a[i] * b[i];
    	fwt(a, -1);
    	a[0] -= n;
    	for(int i = 0 ; i < N ; ++i) a[i] /= 2;
    	
    	
    	for(int j = 0 ; j < m ; ++j){
    		for(int i = 0 ; i < (1 << m) ; ++i){
    			if((i>>j) & 1) {
    				a[i] = a[i] + a[i^(1<<j)];
    			}
    		}
    	}
    	
    	int ans = 0;
    	ll lim = 1ll*n*(n-1)/2-k;
    	int all = (1 << m) - 1;
    	for(int i = 0 ; i < N ; ++i){
    		if(a[all^i] <= lim) ++ans;
    	}
    	printf("%d
    ", ans);
    	
    	return 0;
    }
    
  • 相关阅读:
    [Node.js]连接mongodb
    Vue中computed,methods,watch用法上的异同
    Vue中computed,methods,watch用法上的异同
    Vue method与computed的区别
    60分钟学会使用Node.js+Express+Ejs+mongoDB
    vue.js移动端app实战3:从一个购物车入门vuex
    基于Vue + Node.js + MongoDB的图片上传组件,实现图片的预览和删除
    【Java】线程的 6 种状态
    【Java】线程的创建方式
    如何愉快地通过命令安装Python库
  • 原文地址:https://www.cnblogs.com/tuchen/p/15359118.html
Copyright © 2020-2023  润新知