• 【题解】 神仙的游戏 FWT


    Legend

    ...

    (校内 OJ 题目不公开)

    Link ( extrm{to HOJ})

    Editorial

    (n) 特别小,考虑对每一列状压为 (n) 位二进制数。

    对于每一行,考虑是否翻转, 则对于每一列可以贪心。但这样做复杂度太高。有没有办法可以一次性求出所有情况的答案?

    答案是有,设 (H(i)) 为行翻转状态为 (i) 的答案,(F(i)) 为最初的列为 (i) 的列有多少个,(G(i)) 表示状态为 (i) 的列翻或不翻的最小代价,则:

    [egin{aligned} H(k)&=sum_{i=0}^{2^n-1}F(i)G(ioplus k)\ &=sum_{i=0}^{2^n-1}sum_{j=0}^{2^n-1}[ioplus k=j]F(i)G(j)\ &=sum_{i=0}^{2^n-1}sum_{j=0}^{2^n-1}[ioplus j=k]F(i)G(j) end{aligned} ]

    你惊人地发现这就是个异或 FWT!

    时间复杂度 (O(nm+n2^n))

    Code

    #include <bits/stdc++.h>
    
    #define debug(...) ;//fprintf(stderr ,__VA_ARGS__)
    #define __FILE(x)
    	freopen(#x".in" ,"r" ,stdin);
    	freopen(#x".out" ,"w" ,stdout)
    #define LL long long
    
    const int MX = 1 << 20;
    const LL MOD = 1e9 + 7;
    const LL inv = (MOD + 1) / 2;
    
    int read(){
    	char k = getchar(); int x = 0;
    	while(k < '0' || k > '9') k = getchar();
    	while(k >= '0' && k <= '9') x = x * 10 + k - '0' ,k = getchar();
    	return x;
    }
    
    void chkmin(int &a ,int b){a = std::min(a ,b);}
    int bitcnt(int a){
    	int x = 0;
    	while(a) a -= a & -a ,++x;
    	return x;
    }
    
    char str[20][MX];
    int n ,m ,cnt[MX];
    
    int G[MX] ,F[MX];
    void FWT(int *A ,int limit ,int type){
    	for(int mid = 1 ; mid < limit ; mid <<= 1)
    		for(int j = 0 ; j < limit ; j += mid << 1)
    			for(int k = 0 ; k < mid ; ++k){
    				LL x = A[j + k] ,y = A[j + k + mid];
    				A[j + k] = (x + y) % MOD;
    				A[j + k + mid] = (x - y + MOD) % MOD;
    				if(type == -1){
    					A[j + k] = A[j + k] * inv % MOD;
    					A[j + k + mid] = A[j + k + mid] * inv % MOD;
    				}
    			}
    }
    
    int main(){
    	__FILE(game);
    	n = read() ,m = read();
    	for(int i = 0 ; i < n ; ++i) scanf("%s" ,str[i]);
    	for(int j = 0 ; j < m ; ++j){
    		int a = 0;
    		for(int i = 0 ; i < n ; ++i){
    			a |= (str[i][j] == '1') << i;
    		}
    		++F[a];
    	}
    	for(int i = 0 ; i < (1 << n) ; ++i){
    		int c = bitcnt(i);
    		G[i] = std::min(c ,n - c);
    	}
    
    	int limit = 1 << n;
    	FWT(F ,limit ,1) ,FWT(G ,limit ,1);
    	for(int i = 0 ; i < (1 << n) ; ++i) F[i] = 1LL * F[i] * G[i] % MOD;
    	FWT(F ,limit ,-1);
    	
    	int ans = MX;
    	for(int i = 0 ; i < (1 << n) ; ++i)
    		ans = std::min(ans ,F[i]);
    	printf("%d
    " ,ans);	
    	return 0;
    }
    
  • 相关阅读:
    部门创建注意问题
    我的技术博客开通啦~
    听侯钟雷老师的讲座,确认了几个问题。
    Dynamics CRM 批量添加用户时,报错:Server was unable to process request.
    汉字的Unicode范围(转)
    转载:Apache1.1 post请求无body的bug
    转载:Android有效解决加载大图片时内存溢出的问题
    2.2之前的webkit crash问题
    转载:Expect:100Continue & HTTP 417 Expectation
    城市旅游问题
  • 原文地址:https://www.cnblogs.com/imakf/p/14471316.html
Copyright © 2020-2023  润新知