zoukankan      html  css  js  c++  java
  • Codeforces663E. Binary Table

    $n leq 20,m leq 100000$的01矩阵,可整行整列01翻转,问最少剩几个1.

    一个暴力的做法是枚举$2^n$种行翻转然后$m$列扫一遍。但其实在行翻转情况确定的情况下我们只关心两个东西:某一列在行翻转后剩几个1,以及有几个这样的列。$f(i,j)$--在行翻转$j$的情况下,有$i$个1的有多少列。其实就是与$j$有$i$个位不同的有多少列。可以枚举每一个位置$p$,那么这一位上与$j$不同的状态$f(i-1,j xor 2^p)$可以加过来,但要挑去其中$p$已经算过一次的情况,有$f(i-2,j)$这么多种,又要从$f(i-2,j)$中挑去那些$p$这一位算过一次的情况,$f(i-3,j xor 2^p)$,如此循环。但这样枚举完每个位置之后,每种好的情况其实算了$i$次,所以$i imes f(i,j)=sum_{p=0}^{n-1} sum_{t=1}^{i}(-1)^{t-1}f(i-t,j xor (2^p imes (t mod 2)))$。

    这样是$2^nn^3$的,但可以发现$sum_{p=0}^{n-1}sum_{t=3}^{i}(-1)^{t-1}f(i-t,j xor (2^p imes (t mod 2)))=(i-2) imes f(i-2,j)$,所以整理一下,$i imes f(i,j)=sum_{p=0}^{n-1}f(i-1,j xor 2^p)+(i-2-n)f(i-2,j)$。少一个$n$。

    要再少一个得用FWT。不会。

     1 //#include<iostream>
     2 #include<cstring>
     3 #include<cstdio>
     4 //#include<math.h>
     5 //#include<set>
     6 //#include<queue>
     7 //#include<bitset>
     8 //#include<vector>
     9 #include<algorithm>
    10 #include<stdlib.h>
    11 using namespace std;
    12 
    13 #define LL long long
    14 int qread()
    15 {
    16     char c; int s=0,f=1; while ((c=getchar())<'0' || c>'9') (c=='-') && (f=-1);
    17     do s=s*10+c-'0'; while ((c=getchar())>='0' && c<='9'); return s*f;
    18 }
    19 
    20 //Pay attention to '-' , LL and double of qread!!!!
    21 
    22 int K,n;
    23 #define maxn 1100011
    24 int b[maxn],f[22][maxn];
    25 
    26 int main()
    27 {
    28     K=qread(); n=qread();
    29     {
    30         char c;
    31         for (int i=0;i<K;i++)
    32             for (int j=1;j<=n;j++)
    33             {
    34                 while ((c=getchar())!='0' && c!='1');
    35                 b[j]|=(c-'0')<<i;
    36             }
    37         for (int i=1;i<=n;i++) f[0][b[i]]++;
    38     }
    39     int T=1<<K,ans=0x3f3f3f3f;
    40     for (int i=1;i<=K;i++)
    41     {
    42         for (int j=0;j<T;j++)
    43         {
    44             if (i>1) f[i][j]=(i-2-K)*f[i-2][j];
    45             for (int k=0;k<K;k++) f[i][j]+=f[i-1][j^(1<<k)];
    46             f[i][j]/=i;
    47         }
    48     }
    49     for (int i=0;i<T;i++)
    50     {
    51         int tmp=0;
    52         for (int j=0;j<=K;j++) tmp+=min(j,K-j)*f[j][i];
    53         ans=min(ans,tmp);
    54     }
    55     printf("%d
    ",ans);
    56     return 0;
    57 }
    View Code
  • 相关阅读:
    AOP 学习
    微服务架构理解[架构图](转)
    C# TSC打印二维码和条形码(转)
    C#注册表操作类--完整优化版(转)
    C#调用TSC条码打印机打印二维码(转)
    C#调用TSC条码打印机打印条码(转)
    TSC打印机使用教程终极版(转)
    海尔电商峰值系统架构设计最佳实践(转)
    亿级Web系统搭建——单机到分布式集群(转)
    数据库扩展性设计:使用二进制解决一条记录关联多个状态的问题(转),可以尝试一下
  • 原文地址:https://www.cnblogs.com/Blue233333/p/9206929.html
Copyright © 2011-2022 走看看