1. 程式人生 > >[BZOJ 2064]分裂

[BZOJ 2064]分裂

兩個 最終 中國 out 我們 get lap align 可能

[BZOJ 2064]分裂

題目

背景: 和久必分,分久必和。。。 題目描述: 中國歷史上上分分和和次數非常多。。通讀中國歷史的WJMZBMR表示毫無壓力。 同時經常搞OI的他把這個變成了一個數學模型。 假設中國的國土總和是不變的。 每個國家都可以用他的國土面積代替, 又兩種可能,一種是兩個國家合並為1個,那麽新國家的面積為兩者之和。 一種是一個國家分裂為2個,那麽2個新國家的面積之和為原國家的面積。 WJMZBMR現在知道了很遙遠的過去中國的狀態,又知道了中國現在的狀態,想知道至少要幾次操作(分裂和合並各算一次操作),能讓中國從當時狀態到達現在的狀態。

INPUT

第一行一個數n1,表示當時的塊數,接下來n1個數分別表示各塊的面積。 第二行一個數n2,表示現在的塊,接下來n2個數分別表示各塊的面積。

OUTPUT

一行一個數表示最小次數。

SAMPLE

INPUT

1 6

3 1 2 3

OUTPUT

2

解題報告

這狀壓有毒= =

我們考慮,在最壞的情況下,肯定就是把所有的合起來,再分裂成終態,這樣的答案是$n+m-2$

然而顯然,當我們可以從第一個數列中選出一些數的和與第二個數列中的某些數的和相等時,我們就沒有必要完全合並它們再分裂,次數就減少了$2$

設$f[i]$表示狀態為$i$的有多少組滿足以上條件,則總方案數為$n+m-2-2\times f[(1<<(n+m))-1]$,但是顯然會多算一個$0$的情況,所以最終答案為$n+m-2\times f[(1<<(n+m))-1]$

接下來就是如何轉移了,我們令以前的和為正,現在的為負,則和為$0$就可以湊成一組滿足條件的

所以我們引入數組$sum$,$sum[i]$表示狀態$i$的面積之和,則我們可以遞推求解,$sum[i]=sum[lowbit(i)]+sum[i-lowbit(i)]$

然後直接轉移就行了

技術分享
 1 #include<algorithm>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<cstdio>
 5 using namespace std;
 6 inline int
read(){ 7 int sum(0); 8 char ch(getchar()); 9 for(;ch<0||ch>9;ch=getchar()); 10 for(;ch>=0&&ch<=9;sum=sum*10+(ch^48),ch=getchar()); 11 return sum; 12 } 13 int n1,n2,n,st; 14 int sum[1<<21],f[1<<21]; 15 inline int lowbit(int x){ 16 return x&-x; 17 } 18 int main(){ 19 n1=read(); 20 for(int i=1;i<=n1;++i) 21 sum[1<<(i-1)]=read(); 22 n2=read(); 23 for(int i=n1+1;i<=n1+n2;++i) 24 sum[1<<(i-1)]=-read(); 25 n=n1+n2,st=(1<<n)-1; 26 for(int i=1;i<=st;++i){ 27 sum[i]=sum[lowbit(i)]+sum[i^lowbit(i)]; 28 for(int j=1;j<=n;++j) 29 if(i&(1<<(j-1))){ 30 int tmp(i-(1<<(j-1))); 31 f[i]=max(f[i],f[tmp]); 32 } 33 if(!sum[i]) 34 ++f[i]; 35 } 36 printf("%d",n-(f[st]<<1)); 37 }
View Code

[BZOJ 2064]分裂