日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

[BZOJ] 2064: 分裂

發布時間:2023/12/15 编程问答 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [BZOJ] 2064: 分裂 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

注意到\(n\)很小,應該是狀壓DP

記原集合為\(S\),目標集合為\(T\),如果我們能把\(S\)分成\(x\)個不相交的非空子集,且這\(x\)個子集能和\(T\)中的一些不相交非空子集的和相等,那么最終答案就是\(n+m-2x\),其中\(n=|S|,m=|T|\)

因此我們要最大化\(x\),這就是DP的目標了

\(f[x][y]\)表示\(S\)的子集\(x\)\(T\)的子集\(y\)\(sum\)相等的最多能配幾對

\(sum[x]\not=sum[y]\),枚舉刪去\(x\)\(y\)的一個元素
\[ f[x][y]=max\{f[x\oplus i][y],f[x][y\oplus j]\} \]
\(sum[x]=sum[y]\),情況看起來復雜了

為了轉移,我們似乎要再枚舉子集,復雜度不能接受

但是這樣想,既然\(sum[x]=sum[y]\),那么\(x\)\(y\)至少配成了一對,若在其中刪去一個元素,一定會減少一對

因此
\[ f[x][y]=1+max\{f[x\oplus i][y],f[x][y\oplus j]\} \]
這樣省去了枚舉子集,復雜度有保障

最終復雜度\(O((n+m)2^{n+m})\)

騷操作:如何統計\(sum[x]\)

以前一直寫

for(int S=0;S<(1<<n);S++)for(int i=0;i<n;i++)if(S&(1<<i))sum[S]+=a[i];

這樣做是\(O(n2^n)\)的,實際上,完全可以省去一個\(O(n)\) (雖然\(n\)很小..)

類似統計二進制中1的個數一樣,可以復用\(S\)的子集,方法就是用lowbit

也就是\(sum[x]=sum[x\oplus lowbit(x)]+sum[lowbit(x)]\)

邊界是\(sum[1<<i]=a[i+1]\)

這樣是\(O(2^n)\)

#include<algorithm> #include<iostream> #include<cstdio>using namespace std;inline int rd(){int ret=0,f=1;char c;while(c=getchar(),!isdigit(c))f=c=='-'?-1:1;while(isdigit(c))ret=ret*10+c-'0',c=getchar();return ret*f; } #define space putchar(' ') #define nextline putchar('\n') void _(int x){if(!x)return;_(x/10);putchar('0'+x%10);} void out(int x){if(!x)putchar('0');_(x);}const int MAXN = 10;inline void upmax(int &x,int y){x=max(x,y);}int a[MAXN],b[MAXN]; int f[1<<MAXN][1<<MAXN]; int sum1[1<<MAXN],sum2[1<<MAXN]; int n,m;int main(){n=rd();for(int i=1;i<=n;i++)sum1[1<<(i-1)]=a[i]=rd();m=rd();for(int i=1;i<=m;i++)sum2[1<<(i-1)]=b[i]=rd();for(int i=1;i<(1<<n);i++){sum1[i]=sum1[i^(i&-i)]+sum1[i&-i];}for(int i=1;i<(1<<m);i++){sum2[i]=sum2[i^(i&-i)]+sum2[i&-i];}for(int s=1;s<(1<<n);s++){for(int t=1;t<(1<<m);t++){for(int i=0;i<n;i++){if(s&(1<<i)) upmax(f[s][t],f[s^(1<<i)][t]);}for(int i=0;i<m;i++){if(t&(1<<i)) upmax(f[s][t],f[s][t^(1<<i)]);}if(sum1[s]==sum2[t])f[s][t]++;}}cout<<n+m-2*f[(1<<n)-1][(1<<m)-1];return 0; } 

轉載于:https://www.cnblogs.com/ghostcai/p/9802403.html

總結

以上是生活随笔為你收集整理的[BZOJ] 2064: 分裂的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。