• CF662 C. Binary Table


    题目传送门:CF

    题目大意:

    给定一个(n imes m)的表格((nleqslant 20,mleqslant 10^5))

    每个表格中有(0/1),每次可以将一行或者一列翻转,问表格中最少有多少个1


    首先(n)很小,状压是肯定躲不掉了……

    然后我们发现,只要确定了翻转一些行,那么答案必然唯一确定(每列取(min{Num_0,Num_1})

    于是我们设(f[i])表示翻转行状态为(i)的答案

    统计答案的时候,相同状态的列是可以合并的,所以我们设(C[i])表示列状态为(i)的列个数

    然后我们假定当前列状态为(i),翻转的行状态为(S),那么翻转后状态就为(ioplus S)

    然后对于每一列的任意状态(i),我们都知道其答案,为(min{Num_0,Num_1}),预处理为(g[i])

    那么答案即为(f[k]=sumlimits_{ioplus j=k}C[i] imes g[j])

    FWT优化xor卷积即可

    /*program from Wolfycz*/
    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define inf 0x7f7f7f7f
    #define lowbit(x) ((x)&-(x))
    using namespace std;
    typedef long long ll;
    typedef unsigned int ui;
    typedef unsigned long long ull;
    inline char gc(){
    	static char buf[1000000],*p1=buf,*p2=buf;
    	return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;
    }
    inline int frd(){
    	int x=0,f=1; char ch=gc();
    	for (;ch<'0'||ch>'9';ch=gc())   if (ch=='-')	f=-1;
    	for (;ch>='0'&&ch<='9';ch=gc()) x=(x<<3)+(x<<1)+ch-'0';
    	return x*f;
    }
    inline int read(){
    	int x=0,f=1; char ch=getchar();
    	for (;ch<'0'||ch>'9';ch=getchar())  if (ch=='-')	f=-1;
    	for (;ch>='0'&&ch<='9';ch=getchar())	x=(x<<3)+(x<<1)+ch-'0';
    	return x*f;
    }
    inline void print(int x){
    	if (x<0)	putchar('-'),x=-x;
    	if (x>9)	print(x/10);
    	putchar(x%10+'0');
    }
    const int N=1e5;
    void FWT(ll *a,int n,int type){
    	for (int i=2;i<=n;i<<=1){
    		for (int j=0;j<n;j+=i){
    			for (int k=0;k<i>>1;k++){
    				ll x=a[j+k],y=a[j+k+(i>>1)];
    				a[j+k]=x+y,a[j+k+(i>>1)]=x-y;
    				if (!~type)	a[j+k]>>=1,a[j+k+(i>>1)]>>=1;
    			}
    		}
    	}
    }
    ll f[(1<<20)+10],A[(1<<20)+10],B[(1<<20)+10];
    char s[25][N+10];
    int main(){
    	int n=read(),m=read();ll Ans=inf;
    	for (int i=0;i<n;i++)	scanf("%s",s[i]);
    	for (int j=0;j<m;j++){
    		int sta=0;
    		for (int i=0;i<n;i++)	sta=(sta<<1)+s[i][j]-'0';
    		A[sta]++;
    	}
    	for (int i=1;i<1<<n;i++)	B[i]=B[i-lowbit(i)]+1;
    	for (int i=0;i<1<<n;i++)	B[i]=min(B[i],n-B[i]);
    	FWT(A,1<<n,1),FWT(B,1<<n,1);
    	for (int i=0;i<1<<n;i++)	f[i]=A[i]*B[i];
    	FWT(f,1<<n,-1);
    	for (int i=0;i<1<<n;i++)	Ans=min(Ans,f[i]);
    	printf("%lld
    ",Ans);
    	return 0;
    }
    
  • 相关阅读:
    30-Transformation(HDU4578)-区间线段树(复杂)
    87-区间线段树(板子)--那个苑区的人最瘦
    86-区间线段树-模板
    1-2018-3-2小球碰撞
    85-取石子-威佐夫博弈
    83-取石子-尼姆博弈
    82-珠子染色-置换群
    2018.3.29 设计模式之单例模式详解
    2018.3.27 Mac 配置Tomcat
    2018.3.26 Linux下学习命令
  • 原文地址:https://www.cnblogs.com/Wolfycz/p/10436637.html
Copyright © 2020-2023  润新知