首页 > 代码库 > Codeforces 662C(快速沃尔什变换 FWT)
Codeforces 662C(快速沃尔什变换 FWT)
感觉快速沃尔什变换和快速傅里叶变换有很大的区别啊orz
不是很明白为什么位运算也可以叫做卷积(或许不应该叫卷积吧)
我是看 http://blog.csdn.net/liangzhaoyang1/article/details/52819835 里的快速沃尔什变换
这里说一下自己的理解吧,快速傅里叶变换是计算卷积的,就是∑f(x)*g(n-x)这种
快速沃尔什变换也是计算∑f(x)*g(y) ,但这里是计算所有的满足x^y = n(卷积是计算x+y=n)的和
当然,异或也可以换成&,|这些运算符。
正是因为这一点不同,所以fwt与fft有不同的构造方式,具体见引用的博客里的内容
下面说这道题的题解
题意很简单:就是给出一个01矩阵,每一次可以把一行或一列翻转,不限次数,计算最少有多少个1
首先,每一行只需被翻一次或者不翻,可以证明翻奇数次和翻一次等价,不翻和翻偶数次等价
所以就可以先暴力枚举某一行翻没翻,这样有一个m*2^n的复杂度。
那么怎么考虑用fwt呢
考虑一个翻的方案S,实际上第i列答案就是 min(f(S^a[i]), n - f(S^a[i])) (f可以计算1的个数)
所以也就是说,所有的S^a[i]为同一个值的答案是相同的(想一想x^y=n)
那么就处理出来dp[i] = min(f(i), n - f(i))和原矩阵的列中有多少个是i
对于一个方案S, 答案就是∑dp[S^i]*num[i] (注意x^y = S)
所以我们只需要算出dp和num的卷积,然后从中统计答案即可
#include <iostream> #include <cstdio> #include <cstring> using namespace std; typedef long long LL; class FWT{ public: void fwt(LL *a, int n){ for(int d = 1; d < n; d <<= 1){ for(int m = d<<1, i = 0; i < n; i += m){ for(int j = 0; j < d; j++){ LL x = a[i+j], y = a[i+j+d]; a[i+j] = x+y; a[i+j+d] = x-y; //and a[i+j] = x+y; //or a[i+j+d] = x+y; } } } } void ufwt(LL *a, int n){ for(int d = 1; d < n; d <<= 1){ for(int m = d<<1, i = 0; i < n; i += m){ for(int j = 0; j < d; j++){ LL x = a[i+j], y = a[i+j+d]; a[i+j] = (x+y)/2; a[i+j+d] = (x-y)/2; //and a[i+j] = x-y //or a[i+j] = y-x } } } } void work(LL *a, LL *b, int n){ fwt(a, n); fwt(b, n); for(int i = 0; i < n; i++) a[i] *= b[i]; ufwt(a, n); } }myfwt; const int maxn = 100086; char str[maxn]; LL dp[(1<<20)+5], num[(1<<20)+5], a[maxn]; int n, m; int calc(int x){ int ans = 0; for(; x; x >>= 1) ans += (x&1); return ans; } int main() { cin>>n>>m; for(int i = 0; i < n; i++){ cin>>str; for(int j = 0; j < m; j++) a[j] |= ( (str[j]-‘0‘) << i); } for(int i = 0; i < m; i++) num[a[i]]++; for(int i = 0; i < (1<<n); i++){ int ans = calc(i); dp[i] = min(ans, n-ans); } myfwt.work(dp, num, 1<<n); LL ans = 1e18; for(int i = 0; i < (1<<n); i++) ans = min(ans, dp[i]); cout<<ans<<endl; return 0; }
Codeforces 662C(快速沃尔什变换 FWT)
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。