標籤:bsp define names har sdi 狀態 tmp lag 最大值
Description背景: 和久必分,分久必和。。。 題目描述: 中國歷史上上分分和和次數非常多。。通讀中國歷史的WJMZBMR表示毫無壓力。 同時經常搞OI的他把這個變成了一個數學模型。 假設中國的國土總和是不變的。 每個國家都可以用他的國土面積代替, 又兩種可能,一種是兩個國家合并為1個,那麼新國家的面積為兩者之和。 一種是一個國家分裂為2個,那麼2個新國家的面積之和為原國家的面積。 WJMZBMR現在知道了很遙遠的過去中國的狀態,又知道了中國現在的狀態,想知道至少要幾次操作(分裂和合并各算一次操作),能讓中國從當時狀態到達現在的狀態。Input第一行一個數n1,表示當時的塊數,接下來n1個數分別表示各塊的面積。 第二行一個數n2,表示現在的塊,接下來n2個數分別表示各塊的面積。Output一行一個數表示最小次數。Sample Input1 6
3 1 2 3
Sample Output2
資料範圍:
對於100%的資料,n1,n2<=10,每個數<=50
對於30%的資料,n1,n2<=6, 這狀壓的思路真是神仙啊……首先,最壞的情況就是把上面的合成一堆,然後再分成下面的,於是次數為$n+m-2$然後考慮如何減少次數。如果上面的可以被合成2塊,下面的也可以合成2塊,且上下兩塊的值分別相等,那麼就可以減少一次合并和一次分開,總次數減少了2於是發現如果上下可以被分成值相等的$k$塊,那麼總的次數是$n+m-2*k$然後現在就是要求$k$的最大值了我們用二進位表示某一個數選或不選。如果一個數是上面的,令它值為正,下面的則值為負然後如果上面的一塊和下面的一塊值對應相等的話,就是所有的值加起來為0這樣如果某一個子集的和為0,就說明它可以互相變化於是令$dp[i]$表示選的狀態為$i$時的最大的$k$,因為只有在$sum[i]==0$時,$dp[i]++$,其他狀態都只能直接轉移
1 //minamoto 2 #include<bits/stdc++.h> 3 using namespace std; 4 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++) 5 char buf[1<<21],*p1=buf,*p2=buf; 6 template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;} 7 inline int read(){ 8 #define num ch-‘0‘ 9 char ch;bool flag=0;int res;10 while(!isdigit(ch=getc()))11 (ch==‘-‘)&&(flag=true);12 for(res=num;isdigit(ch=getc());res=res*10+num);13 (flag)&&(res=-res);14 #undef num15 return res;16 }17 const int N=2e6+5;18 int n,m,sum[N],dp[N],lim;19 int main(){20 // freopen("testdata.in","r",stdin);21 n=read();for(int i=1;i<=n;++i) sum[1<<(i-1)]=read();22 m=read();for(int i=1;i<=m;++i) sum[1<<(i+n-1)]=-read();23 lim=1<<(n+m);24 for(int i=1;i<lim;++i){25 int tmp=i&-i;sum[i]=sum[tmp]+sum[i-tmp];26 for(int j=1;j<=n+m;++j)27 if(i&(1<<(j-1))) cmax(dp[i],dp[i-(1<<(j-1))]);28 if(!sum[i]) ++dp[i];29 }30 printf("%d\n",n+m-2*dp[lim-1]);31 return 0;32 }
bzoj2064: 分裂(狀壓dp)