zoukankan      html  css  js  c++  java
  • CF662C Binary Table

    一道(FWT).
    题目链接


    题目概述

    有一个(n)(m)列的表格,每格中都有(0)(1).
    每次操作可以将某行或某列取反.
    操作次数无限,求最后表格中最少有多少个(1).
    (nleq 20,mleq 100000)


    解析

    我们先想一个简单的暴力.
    考虑暴力枚举每行是否取反.假设状态是(S).
    相当于每列的数都异或上(S).然后预处理(popcount)计算,取异或结果中(0/1)数量的较小值即可(因为可以通过取反一列来改变).
    时间复杂度(O(2^n*m)),无法通过本题.

    考虑如何优化.
    首先先把每一列表示的二进制数记录下来.
    (a_i)表示(i)这个数在表格中出现了几次,
    再令(b_i)表示(min(popcount(i),n-popcount(i)))
    那么假设枚举的状态是(S),那么此时对应的答案(ans_S=sum_{i=0}^{2^n}a_i*b_{ioplus S})
    换一种表现形式就是(ans_S=sum_{ioplus j=S}a_ib_j)
    那么就直接(FWT)即可.
    时间复杂度(O(2^n*n))

    代码如下
    真的超级短呢

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<vector>
    #define N (1<<21)
    #define M (100010)
    #define inf (0x7f7f7f7f)
    #define rg register int
    #define Label puts("NAIVE")
    #define spa print(' ')
    #define ent print('
    ')
    #define rand() (((rand())<<(15))^(rand()))
    typedef long double ld;
    typedef long long LL;
    typedef unsigned long long ull;
    using namespace std;
    inline char read(){
    	static const int IN_LEN=1000000;
    	static char buf[IN_LEN],*s,*t;
    	return (s==t?t=(s=buf)+fread(buf,1,IN_LEN,stdin),(s==t?-1:*s++):*s++);
    }
    template<class T>
    inline void read(T &x){
    	static bool iosig;
    	static char c;
    	for(iosig=false,c=read();!isdigit(c);c=read()){
    		if(c=='-')iosig=true;
    		if(c==-1)return;
    	}
    	for(x=0;isdigit(c);c=read())x=((x+(x<<2))<<1)+(c^'0');
    	if(iosig)x=-x;
    }
    inline char readchar(){
    	static char c;
    	for(c=read();!isalpha(c)&&!isdigit(c);c=read())
    	if(c==-1)return 0;
    	return c;
    }
    const int OUT_LEN = 10000000;
    char obuf[OUT_LEN],*ooh=obuf;
    inline void print(char c) {
    	if(ooh==obuf+OUT_LEN)fwrite(obuf,1,OUT_LEN,stdout),ooh=obuf;
    	*ooh++=c;
    }
    template<class T>
    inline void print(T x){
    	static int buf[30],cnt;
    	if(x==0)print('0');
    	else{
    		if(x<0)print('-'),x=-x;
    		for(cnt=0;x;x/=10)buf[++cnt]=x%10+48;
    		while(cnt)print((char)buf[cnt--]);
    	}
    }
    inline void flush(){fwrite(obuf,1,ooh-obuf,stdout);}
    int n,m,num[M],Lim,pc[N];
    LL a[N],b[N],ans=1e18;
    void FWT(LL *a,int tp){
    	for(int i=1;i<Lim;i<<=1)
    	for(int R=i<<1,j=0;j<Lim;j+=R)
    	for(int k=j;k<j+i;k++){
    		LL x=a[k],y=a[k+i];
    		a[k]=x+y,a[k+i]=x-y;
    		if(tp==-1)a[k]/=2,a[k+i]/=2;
    	}
    }
    int main(){
    	read(n),read(m),Lim=(1<<n);
    	for(int i=1;i<=n;i++)
    	for(int j=1;j<=m;j++)
    	(num[j]=(num[j]<<1)+readchar()-'0');
    	for(int i=1;i<=m;i++)
    	a[num[i]]++;
    	for(int i=1;i<Lim;i++)
    	pc[i]=pc[i>>1]+(i&1),b[i]=min(pc[i],n-pc[i]);
    	FWT(a,1),FWT(b,1);
    	for(int i=0;i<Lim;i++)a[i]=(a[i]*b[i]);
    	FWT(a,-1);
    	for(int i=0;i<Lim;i++)ans=min(ans,a[i]);
    	printf("%lld
    ",ans);
    }
    
  • 相关阅读:
    java.lang.NoClassDefFoundError: org/hibernate/service/ServiceRegistry] 类似问题
    哪些window你不知道的却实用的小技巧----window小技巧
    windows命令快捷启动应用-----window小技巧
    cmd窗口关闭 -----window小技巧!
    Eclipse错误笔记!
    如何在WIndows电脑上安装 SVN Server 实现代码版本控制
    linux之应用开发杂记(一)
    面试知识点汇总
    Android技术面试整理
    MYSQL常用操作语句
  • 原文地址:https://www.cnblogs.com/Romeolong/p/10075309.html
Copyright © 2011-2022 走看看