码迷,mamicode.com
首页 > 其他好文 > 详细

CF662C Binary Table(FWT)

时间:2019-01-15 15:53:46      阅读:162      评论:0      收藏:0      [点我收藏+]

标签:出现   ace   freopen   binary   etc   一个   open   ons   次数   

  注意到n很小,显然的做法是枚举每行是否翻转,然后O(m)统计Σmin(popcount(ai),n-popcount(ai))即可。考虑将每列是否翻转写成一个二进制数,那么翻转相当于让该二进制数与每列异或。统计每列各种状态的出现次数,将其设为cnt[i],将min(popcount(i),n-popcount(i))设为g[i],可以发现若翻转状态为j,答案即为Σcnt[i]·g[i^j]。这就是一个异或卷积,FWT就行了。

#include<bits/stdc++.h>
using namespace std;
int getbit(){char c=getchar();while (c<0||c>9) c=getchar();return c^48;}
int read()
{
    int x=0,f=1;char c=getchar();
    while (c<0||c>9) {if (c==-) f=-1;c=getchar();}
    while (c>=0&&c<=9) x=(x<<1)+(x<<3)+(c^48),c=getchar();
    return x*f; 
}
#define N (1<<20)
#define M 100010
#define P 1000000007 
#define inv2 500000004
int n,m,a[M],cnt[N],g[N],ans;
void FWT(int *a,int n,int op)
{
    for (int i=2;i<=n;i<<=1)
        for (int j=0;j<n;j+=i)
            for (int k=j;k<j+(i>>1);k++)
            {
                int x=a[k],y=a[k+(i>>1)];
                a[k]=(x+y)%P,a[k+(i>>1)]=(x-y+P)%P;
                if (op) a[k]=1ll*a[k]*inv2%P,a[k+(i>>1)]=1ll*a[k+(i>>1)]*inv2%P;
            }
}
int main()
{
#ifndef ONLINE_JUDGE
    freopen("a.in","r",stdin);
    freopen("a.out","w",stdout);
    const char LL[]="%I64d\n";
#else
    const char LL[]="%lld\n";
#endif
    n=read(),m=read();
    for (int i=0;i<n;i++)
        for (int j=1;j<=m;j++)
        a[j]|=getbit()<<i;
    for (int i=1;i<=m;i++) cnt[a[i]]++;
    for (int i=1;i<(1<<n);i++) g[i]=g[i^(i&-i)]+1;
    for (int i=1;i<(1<<n);i++) g[i]=min(g[i],n-g[i]);
    FWT(g,(1<<n),0),FWT(cnt,(1<<n),0);
    for (int i=0;i<(1<<n);i++) g[i]=1ll*g[i]*cnt[i]%P;
    FWT(g,(1<<n),1);
    ans=n*m;
    for (int i=0;i<(1<<n);i++) ans=min(ans,g[i]);
    cout<<ans;
    return 0;
}

 

CF662C Binary Table(FWT)

标签:出现   ace   freopen   binary   etc   一个   open   ons   次数   

原文地址:https://www.cnblogs.com/Gloid/p/10271801.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!