CF662C Binary Table

  • 链接
  • \(n\leq 20\),枚举列状态,然后\(O(m)\)贪心一下。
  • \(O(2^nm)\),显然过不去。考虑优化一下。
  • \(f_i\)表示状态\(i\)的出现次数,\(g_i\)表示\(i\)状态的贡献,设修改状态\(k\)的答案是\(h_k\),则

\[h_k=\sum_{k\ xor\ i\ =j}f_i*g_j \]

  • 也就是本来\(i\)的个数,现在通过\(k\)变成了\(j\),乘上\(j\)的贡献。
  • \(fwt\)卷一下就可以了。
#include<bits/stdc++.h>
#define R register int
#define ll long long
using namespace std;
const int N=100001;
const int M=1248576;
int n,m,len,x;ll ans,f[M],g[M];
char S[23][N];
int gi(){
    R x=0,k=1;char c=getchar();
    while(c!='-'&&(c<'0'||c>'9'))c=getchar();
    if(c=='-')k=-1,c=getchar();
    while(c<='9'&&c>='0')x=(x<<3)+(x<<1)+c-'0',c=getchar();
    return x*k;
}
void fwt(ll *A,R op){
	for(R i=1;i<len;i<<=1)
		for(R p=(i<<1),j=0;j<len;j+=p)
			for(R k=0;k<i;++k){
				ll x=A[j+k],y=A[j+k+i];
				A[j+k]=(x+y)/op,A[j+k+i]=(x-y)/op;
			}
}
int main(){
	n=gi(),m=gi(),len=(1<<n);
	for(R i=1;i<=n;++i)scanf("%s",S[i]+1);
	for(R i=1;i<=m;++i){
		x=0;
		for(R j=1;j<=n;++j)
			x=(x<<1)+S[j][i]-'0';
		f[x]++;
	}
	for(R i=1;i<len;++i)g[i]=g[i>>1]+(i&1);
	for(R i=1;i<len;++i)g[i]=min(g[i],n-g[i]);
	fwt(f,1),fwt(g,1);
	for(R i=0;i<len;++i)f[i]*=g[i];
	fwt(f,2),ans=f[0];
	for(R i=1;i<len;++i)ans=min(ans,f[i]);
	cout<<ans<<endl;
	return 0;
}

posted @ 2018-11-29 17:22  Tyher  阅读(171)  评论(0编辑  收藏  举报