hdu6092(dp)
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=6092
题意: 输入格式为, 对于每组测试样例第一行输入两个数 n, m, 接下来一行输入B数组, 有 m + 1个数. 其中 n 表示要构造的数组 A 的长度为 n. m 表示 A 数组的元素和为 m. 第二行的m + 1 个数字表示 A 数组 有子集中和为 0, 1, ..., m 的子集个数.
思路: 可以从 1 到 m 依次确定每个数出现的次数. 用 dp[i] 表示当前答案集中和为 i 的子集数.
枚举 1 <= i <= m, 对于当前 i, 其在 A 中出现的次数为 B[i] - dp[i], 每往 A 中添加一个元素更新一次 dp 数组.
更新 dp 的过程可以看作一个 01 背包过程.
代码:
1 #include <iostream> 2 #include <stdio.h> 3 #include <string.h> 4 using namespace std; 5 6 const int MAXN = 1e4 + 10; 7 int dp[MAXN], a[MAXN], sol[MAXN];//dp[i]存储当前答案集中和为i的子集有多少 8 9 int main(void){ 10 int t, n, k; 11 scanf("%d", &t); 12 while(t--){ 13 int indx = 0; 14 memset(dp, 0, sizeof(dp)); 15 scanf("%d%d", &n, &k); 16 for(int i = 0; i <= k; i++){ 17 scanf("%d", &a[i]); 18 } 19 dp[0] = 1; 20 for(int i = 1; i <= k; i++){ 21 int cnt = a[i] - dp[i]; 22 for(int j = 0; j < cnt; j++){ 23 sol[indx++] = i; 24 for(int l = k; l >= i; l--){//注意先更新小的数会影响后面的更新 25 dp[l] += dp[l - i]; 26 } 27 } 28 } 29 for(int i = 0; i < indx; i++){ 30 if(i) printf(" "); 31 printf("%d", sol[i]); 32 } 33 puts(""); 34 } 35 return 0; 36 }
我就是我,颜色不一样的烟火 --- geloutingyu