CF662C-Binary Table【FWT】
生活随笔
收集整理的這篇文章主要介紹了
CF662C-Binary Table【FWT】
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
正題
題目鏈接:https://www.luogu.com.cn/problem/CF662C
題目大意
n?mn*mn?m的網格上有0/10/10/1,可以任意翻轉行和列,求剩下最少的111。
解題思路
知道是FWTFWTFWT之后就好做很多了。
首先因為nnn很小,所以可以考慮枚舉翻轉的行數,我們現在需要對于一個行的翻轉狀態快速知道最小值。
如果一行狀態sss翻轉行狀態www之后就相當于val(sxorw)val(s\ xor\ w)val(s?xor?w)反過來也就是若c=sxorwc=s\ xor\ wc=s?xor?w那么sxorc=ws\ xor\ c=ws?xor?c=w。
此時就可以上FWTFWTFWT了,設valival_ivali?表示列狀態iii的最小值,numinum_inumi?表示列狀態iii的數量。那么ans(s)=∑ixorj=svali×numjans(s)=\sum_{i\ xor\ j=s}val_i\times num_jans(s)=i?xor?j=s∑?vali?×numj?
上FWTFWTFWT即可,時間復雜度O(2nn+nm)O(2^nn+nm)O(2nn+nm)
codecodecode
#include<cstdio> #include<cstring> #include<algorithm> #define ll long long using namespace std; const ll N=(1<<21); ll n,m,val[N],num[N],ans; char s[20][110000]; void FWT(ll *f,ll op){for(ll p=2;p<=n;p<<=1)for(ll k=0,len=p>>1;k<n;k+=p)for(ll i=k;i<k+len;i++){ll x=f[i],y=f[i+len];f[i]=(x+y)/op;f[i+len]=(x-y)/op;}return; } void solve(ll *a,ll *b){FWT(a,1);FWT(b,1);for(ll i=0;i<n;i++)a[i]=a[i]*b[i];FWT(a,2);return; } int main() {scanf("%lld%lld",&n,&m);for(ll i=0;i<n;i++)scanf("%s",s[i]);ll MS=(1<<n);for(ll i=1;i<MS;i++)val[i]=val[i-(i&-i)]+1;for(ll i=0;i<MS;i++)val[i]=min(val[i],n-val[i]);for(ll i=0;i<m;i++){ll w=0;for(ll j=0;j<n;j++)w+=(s[j][i]=='1')<<j;num[w]++;}n=MS;solve(val,num);ans=1e9;for(ll i=0;i<n;i++)ans=min(ans,val[i]);printf("%lld\n",ans); }總結
以上是生活随笔為你收集整理的CF662C-Binary Table【FWT】的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 3d制图电脑配置推荐(做3d的电脑配置)
- 下一篇: CF1119H-Triple【FWT】