問題
FWT用來解決這樣的一個問題:
給出多項式A(x),B(x),求C(x),其中
(也可以換成and/or)
要求在 的複雜度內求出C(x)
定義
定義 操作表示(A是一個長度爲2的冪的多項式,k表示A的長度,A0A1分別表示A的左半邊和右半邊)
則
其中”,”表示物理順序拼接
性質
然後有一條性質
證明略,可以用數學歸納法來證
因爲C=A⊕B,所以可以得出
等於把異或第一位爲0的數加到左邊,異或第一位爲1的數加到右邊
然後xjb證出tf(A)tf(B)=tf(C) (當C=A⊕B時)
所以可以先求出tf(A)和tf(B),之後相乘求逆
逆運算
定義tf(A)的逆運算utf(A),表示utf(tf(A))=A
則
證明還是數學歸納法
所以這樣對tf(C)做utf操作,就可以得出C了
而tf和utf操作都是 的
其它
關於三種運算的tf和utf
其中異或的utf是可以拆的,也就是說utf(A)+utf(B)=utf(A+B)
證明和tf基本一樣(就是多了個/2)
例題
codeforces662CBinary Table 二進制表
C. Binary Table
time limit per test6 seconds
memory limit per test256 megabytes
inputstandard input
outputstandard output
You are given a table consisting of n rows and m columns. Each cell of the table contains either 0 or 1. In one move, you are allowed to pick any row or any column and invert all values, that is, replace 0 by 1 and vice versa.
What is the minimum number of cells with value 1 you can get after applying some number of operations?
Input
The first line of the input contains two integers n and m (1 ≤ n ≤ 20, 1 ≤ m ≤ 100 000) — the number of rows and the number of columns, respectively.
Then n lines follows with the descriptions of the rows. Each line has length m and contains only digits ‘0’ and ‘1’.
Output
Output a single integer — the minimum possible number of ones you can get after applying some sequence of operations.
Example
inputCopy
3 4
0110
1010
0111
outputCopy
2
C.二進制表
每次測試的時間限制6秒
每次測試的內存限制256兆字節
輸入標準輸入
產量標準輸出
您將獲得一個由n行和m列組成的表。表的每個單元格包含0或1。在一個步驟中,您可以選擇任何行或任何列並反轉所有值,即將0替換爲1,反之亦然。
在應用一些操作後,您可以獲得值爲1的最小單元格數是多少?
輸入
輸入的第一行包含兩個整數Ñ和米(1≤ Ñ ≤20,1≤ 米 ≤100 000) -行的,分別的數量和列的數量。
然後n行跟隨行的描述。每行的長度爲m,僅包含數字“ 0 ”和“ 1 ”。
產量
輸出一個整數 - 應用一系列操作後可以獲得的最小數量。
例
輸入複製
3 4
0110
1010
0111
產量複製
2
題解
就是給出一個01矩陣,每次可以把一行或一列取反
求所有可能的矩陣中最小的1個數
因爲n很小,所以考慮狀壓n
如果行的方案確定了,那麼答案就是每一列異或行後取反與否的最大值之和
設f(s)表示當行選取的狀態爲s時的答案
設ans(s)表示某一列狀態爲s時的答案
要考慮整列取反的情況
設g(s)表示初始列狀態爲s的列數
則
等於是枚舉每一種可能的列,然後進行列的取反,答案就是所有列之和
可以變成
就是FWT的形式了
code
// codeforces 662C Binary Table
// start:25/08/17
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define min(a,b) (a<b?a:b)
using namespace std;
typedef long long AA[1048576];
int A[100001];
AA s,a,b,c;
int n,m,i,j,k,l,Len;
char ch;
long long ans;
void tf(long long *a)
{
int i,j,k,l;
int S=1,s1=1,s2=Len+1;
fo(i,1,n)
{
S<<=1;
s2>>=1;
fo(j,0,s2-1)
{
fo(k,0,s1-1)
{
l=j*S+k;
s[l]=a[l]+a[l+s1];
s[l+s1]=a[l]-a[l+s1];
}
}
memcpy(a,s,sizeof(long long)*(Len+1));
s1<<=1;
}
}
void utf(long long *a)
{
int i,j,k,l;
int S=1,s1=1,s2=Len+1;
fo(i,1,n)
{
S<<=1;
s2>>=1;
fo(j,0,s2-1)
{
fo(k,0,s1-1)
{
l=j*S+k;
s[l]=(a[l]+a[l+s1])>>1;
s[l+s1]=(a[l]-a[l+s1])>>1;
}
}
memcpy(a,s,sizeof(long long)*(Len+1));
s1<<=1;
}
}
int main()
{
scanf("%d%d",&n,&m); Len=pow(2,n)-1;
fo(i,1,n)
{
scanf("\n");
fo(j,1,m)
{
scanf("%c",&ch);
A[j]=(A[j]<<1)+(ch-'0');
}
}
fo(i,1,m)
b[A[i]]++;
fo(i,0,Len)
{
j=i;
k=0;
while (j)
{
k+=j&1;
j>>=1;
}
a[i]=min(k,n-k);
}
tf(a);
tf(b);
fo(i,0,Len)
c[i]=a[i]*b[i];
utf(c);
ans=233333333;
fo(i,0,Len)
ans=min(ans,c[i]);
printf("%I64d\n",ans);
}