【题目链接】
http://acm.hdu.edu.cn/showproblem.php?pid=6092
题目意思
T组测试,接下来一行n和m,下面一行m+1个数字代表B(0~m)求A序列,Bi 代表A序列中的所有子集之和为i的有Bi个,A序列总和为m,n个元素;
解题思路
一个0 1背包问题,有空子集等于1可以得出初始值dp【0】=1;然后根据b数组和为i个数-dp中由小数子加和为的个数得出a数组中数值为i的个数。
这题用到的0 1背包,而0 1背包更新都是从后往前的(必须后往前,不然会重复计算)。更新原则:出现一个i;那么dp【k】+=dp【k-i】(如出现了一个2,那么和为5的个数就要加上 和为3个数)
代码部分
#include<bits/stdc++.h>
using namespace std;
#define ll long long
int main()
{
int t;
scanf("%d",&t);
while (t--)
{
int a[10005],b[10005],dp[10005];///dp存储和为i的个数
memset(dp,0,sizeof(dp));
int top=0,n,m;
scanf("%d %d",&n,&m);
for (int i=0; i<=m; i++)
scanf("%d",&b[i]);
dp[0]=1; ///初始化值
for (int i=1; i<=m; i++)
{
int s=b[i]-dp[i]; ///计算a中i的个数
for (int j=0; j<s; j++) ///每次多个i都要更新一次背包
{
a[top++]=i;
for (int k=m; k>=i; k--)///01背包更新
dp[k]+=dp[k-i];
}
}
for(int i = 0; i < n; i++)
{
if(i > 0) printf(" ");
printf("%d", a[i]);//输出A序列
}
printf("\n");
}
return 0;
}