1. 程式人生 > >Codeforces663E. Binary Table

Codeforces663E. Binary Table

技術 getc bin AR -c alt str 兩個 long

$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 \times f(i,j)=\sum_{p=0}^{n-1} \sum_{t=1}^{i}(-1)^{t-1}f(i-t,j \ \ xor \ \ (2^p \times (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 \times (t \mod 2)))=(i-2) \times f(i-2,j)$,所以整理一下,$i \times 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\n",ans); 56 return 0; 57 }
View Code

Codeforces663E. Binary Table