BZOJ2064 分裂

2064: 分裂

Time Limit: 10 Sec  Memory Limit: 64 MB

Description

背景: 和久必分,分久必和。。。 题目描述: 中国历史上上分分和和次数非常多。。通读中国历史的WJMZBMR表示毫无压力。 同时经常搞OI的他把这个变成了一个数学模型。 假设中国的国土总和是不变的。 每个国家都可以用他的国土面积代替, 又两种可能,一种是两个国家合并为1个,那么新国家的面积为两者之和。 一种是一个国家分裂为2个,那么2个新国家的面积之和为原国家的面积。 WJMZBMR现在知道了很遥远的过去中国的状态,又知道了中国现在的状态,想知道至少要几次操作(分裂和合并各算一次操作),能让中国从当时状态到达现在的状态。

Input

第一行一个数n1,表示当时的块数,接下来n1个数分别表示各块的面积。 第二行一个数n2,表示现在的块,接下来n2个数分别表示各块的面积。

Output

一行一个数表示最小次数。

Sample Input

1 6
3 1 2 3

Sample Output

2
数据范围:
对于100%的数据,n1,n2<=10,每个数<=50
对于30%的数据,n1,n2<=6
solution:  
  如果没有任何特殊情况,那么次数就是n1+n2-2,此时我们可以理解为把所有先合并为一个在一个个分开,但其实这有一个前提条件就是合并前的面积和与分裂后的面积和相同,并且每多一个合并前面积等于分裂后的面积和答案减2,例如一开始为2 4 3 分裂或为3 3 3 ,2+4==3+3 3==3,所以我们完全没有必要将2/4/3合并了再分裂,只需要将2/4合并再分裂为3/3,一开始的3直接变为现在的3就好。
     数据范围很小状压DP,设sum[i]为i状态下面积和,f[i]为i状态下有多少块面积和为零的块,n=n1+n2,读入时把n1块的面积设为正,n2块面积设为负,转移很好说了,先让f[i]从子状态从取最大值,如果此时sum[i]==0说明又构成了一个面积和为0的块++f[i],最后答案为n-(f[(1<<n)-1]<<1)
  

 

 1 #include <cstdio>
 2 #include <iostream>
 3 using namespace std;
 4 int sum[1<<21],f[1<<21],n1,n2,n,state;
 5 int lowbit(int x) {return x&(-x);}
 6 int main() {
 7     cin>>n1;
 8     for(int i=1; i<=n1; ++i) cin>>sum[1<<(i-1)];
 9     cin>>n2;
10     for(int i=n1+1; i<=n1+n2; ++i) cin>>sum[(1<<(i-1))],sum[1<<(i-1)]*=-(1);
11     n=n1+n2; state=(1<<n);
12     for(int i=1; i<state; ++i) {
13         sum[i]=sum[lowbit(i)]+sum[i^lowbit(i)];
14         for(int j=1; j<=n; ++j) if(i&(1<<(j-1))) f[i]=max(f[i],f[i^(1<<(j-1))]);
15         if(!sum[i]) ++f[i];
16     } printf("%d",n-2*f[state-1]);
17     return 0;
18 }

 

posted @ 2017-10-19 15:44  Forever_goodboy  阅读(163)  评论(0编辑  收藏  举报