CF662C Binary Table

  • 链接
  • (nleq 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;
}

原文地址:https://www.cnblogs.com/Tyher/p/10039707.html