传送门

题目大意:

给两个数组, 数组中的两个元素可以合并成两元素之和,每个元素都可以分裂成相应的大小,问从数组1变化到数组2至少需要多少步?

题目分析:

看到数据范围\(n<=10\), 显然是在提醒我们状压。用sum[i]表示i状态的面积总和。

对于任意一个数组\(1\)和数组\(2\)(\(sum\)值必须相等才能变化),变化的最劣情况是将数组\(1\)合并成1个再分成数组\(2\),步数为\(n1 + n2 - 2\),然而如果数组\(1\)的一个子集\(k\)和数组\(2\)的一个子集\(l\)的\(sum\)相等,\(k\)和\(l\)又可以以同样的方法进行变化,使数组\(1\)到数组\(2\)的变化次数\(-2 = n1 + n2 - 2 * 2\),继续拓展,也就是说如果存在\(x\)个面积相等的子集,变化次数就为\(n1 + n2 - 2 * x\)。

\(f[i][j]\)表示数组\(1\)的\(i\)状态和数组\(2\)的\(j\)状态存在的相同面积的子集数量,于是就可以枚举子集进行\(dp\)求出\(f[(1 << n1) - 1][(1 << n2) - 1]\),最后答案即为\(n1 + n2 - 2 * f[(1 << n1) - 1][(1 << n2) - 1]\)。

看似复杂度会爆表,其实无用状态很多,因为只有\(sum\)相等才能进行变化。

code

580ms

#include<bits/stdc++.h>
using namespace std; const int N = 15;
int n1, n2, a1[N], a2[N], sum1[1100], sum2[1100], f[1100][1100]; inline int count(int x){
int ret = 0;
while(x) ret++, x = x & (x - 1);
return ret;
} struct ioSys{
inline int read(){
int i = 0, f = 1; char ch = getchar();
for(; (ch < '0' || ch > '9') && ch != '-'; ch = getchar());
if(ch == '-') f = -1, ch = getchar();
for(; ch >= '0' && ch <= '9'; ch = getchar())
i = (i << 3) + (i << 1) + (ch - '0');
return i * f;
} inline void wr(int x){
if(x < 0) putchar('-'), x = -x;
if(x > 9) wr(x / 10);
putchar(x % 10 + '0');
}
inline void operator >> (int &x){
x = read();
}
inline void operator << (int x){
wr(x);
}
}IO; int main(){
freopen("h.in", "r", stdin);
IO >> n1;
for(int i = 1; i <= n1; i++) IO >> a1[i];
for(int i = 0; i <= (1 << n1) - 1; i++){
for(int j = 1; j <= n1; j++)
if((1 << (j - 1)) & i) sum1[i] += a1[j];
// cout<<sum1[i]<<" ";
}
// cout<<endl;
IO >> n2;
for(int i = 1; i <= n2; i++) IO >> a2[i];
for(int i = 0; i <= (1 << n2) - 1; i++){
for(int j = 1; j <= n2; j++)
if((1 << (j - 1)) & i) sum2[i] += a2[j];
// cout<<sum2[i]<<" ";
}
// cout<<endl;
//---------------------------------------
for(int i = 0; i <= (1 << n1) - 1; i++)
for(int j = 0; j <= (1 << n2) - 1; j++){
if(sum1[i] == sum2[j]){
f[i][j]++;
for(int k = i & (i - 1); k; k = i & (k - 1))
for(int l = j & (j - 1); l; l = j & (l - 1)){
// if(sum1[k] == sum2[l]) f[k][l]++;
f[i][j] = max(f[i][j], f[i - k][j - l] + f[k][l]);
}
}
}
// cout<<f[(1 << n1) - 1][(1 << n2) - 1]<<endl;
IO << n1 + n2 - 2 * f[(1 << n1) - 1][(1 << n2) - 1];
}

BZOJ 2064 - 状压DP的更多相关文章

  1. bzoj 1879 状压dp

    879: [Sdoi2009]Bill的挑战 Time Limit: 4 Sec  Memory Limit: 64 MBSubmit: 852  Solved: 435[Submit][Status ...

  2. bzoj 1087 状压dp

    1087: [SCOI2005]互不侵犯King Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 4130  Solved: 2390[Submit][ ...

  3. BZOJ 4057 状压DP

    思路: 状压一下 就完了... f[i]表示选了的集合为i 转移的时候判一判就好了.. //By SiriusRen #include <cstdio> #include <cstr ...

  4. BZOJ 4565 状压DP

    思路: f[i][j][S]表示从i到j压成S状态 j-m是k-1的倍数 $f[i][j][S<<1]=max(f[i][j][S<<1],f[i][m-1][S]+f[m][ ...

  5. bzoj 1072状压DP

    1072: [SCOI2007]排列perm Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 2293  Solved: 1448[Submit][St ...

  6. bzoj 1072 状压DP

    我们用w[i][j]来表示,i是一个二进制表示我们选取了s中的某些位,j表示这些位%d为j,w[i][j]则表示这样情况下的方案数,那么我们可以得到转移.w[i|(1<<k)][(j*10 ...

  7. bzoj 2669 状压DP

    因为最多有8个'X',所以我们可以用w[i][s]来表示现在我们填了前i个数,填的X的为S,因为每次新加进来的数都不影响前面的最小值,所以我们可以随便添加,这样就有了剩下所有位置的方案,每次都这样转移 ...

  8. bzoj 1076 状压DP

    我们设w[i][s]为当前到第i关,手中的物品为s的时候,期望得分为多少,其中s为二进制表示每种物品是否存在. 那么就比较容易转移了w[i][s]=(w[i-1][s']+v[j]) *(1/k),其 ...

  9. BZOJ 1231 状压DP

    思路: f[i][j] i表示集合的组成 j表示选最后一个数 f[i][j]表示能选的方案数 f[i|(1<< k)][k]+=f[i][j]; k不属于i j属于i且符合题意 最后Σf[ ...

随机推荐

  1. ospp.vbs是什么文件?激活过程cscript ospp.vbs命令详解

    ospp.vbs是什么文件?激活过程cscript ospp.vbs命令详解 在Office 2013激活过程中我们经常会用到cscript ospp.vbs这个命令.那么,很有必要来了解一下,osp ...

  2. 右键菜单→新建→BAT 批处理文件

    目的:以前编写BAT,通常新建一个文本,然后另存为 .bat,比较麻烦,那么如何右键新建菜单里添加新建批处理文件呢? 代码如下: @echo offcd /d %temp%echo Windows R ...

  3. input输入框获得、失去焦点添加事件

    onBlur:当输入框失去焦点后 onFocus:当输入框获得焦点后 这两个JavaScript事件是写在html标签中的例如: <input type="text" onB ...

  4. django 简单会议室预约(1)

    django 是python的一个web框架,为什么要用django,作者之前用过另一个框架flask,虽然flask比较简单很容易让人学,但是flask没有整体感,会让初学着茫然. 这里我们用dja ...

  5. C#利用反射机制,获取实例的属性和属性值

    C#利用反射,遍历获得一个类的所有属性名,以及该类的实例的所有属性的值 对应某个类的实例化的对象tc, 遍历获取所有属性(子成员)的方法(采用反射): Type t = tc.GetType();// ...

  6. (转)ipv4的网段表示方法

    简单一点举例说明:ip段:10.0.0.1-10.0.0.255            的表示方法:10.0.0.0/24ip段:10.0.0.1-10.0.255.255        的表示方法: ...

  7. 14、编写一个通用的Makefile

    编译test_Makefile的方法:a. gcc -o test a.c b.c对于a.c: 预处理.编译(C文件转换成汇编).汇编(汇编转换成机器码)对于b.c:预处理.编译.汇编最后链接优点:命 ...

  8. 关于fatfs生成的wav文件是空,大小是0的问题

    绝大多数是因为打开错误 调试的时候,编写程序的时候 要记得res=f_open() 要有返回值res的设置

  9. [CSS] Use Generated Content to Augment Information

    When you create a pseudo element, you have access to the parent HTML attributes. They can be used in ...

  10. <h2>1. mongodb介绍</h2>

    1. mongodb介绍 2. ppt下载地址 http://download.csdn.net/detail/u014285882/7807105 阅读全文 本文已收录于下面专栏: mongodb使 ...