(hdu6092) 2017杭电多校联赛第5场-Rikka with Subset 动态规划

Rikka with Subset

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 837    Accepted Submission(s): 411


Problem Description
As we know, Rikka is poor at math. Yuta is worrying about this situation, so he gives Rikka some math tasks to practice. There is one of them:

Yuta has  n positive  A1An and their sum is  m. Then for each subset  S of  A, Yuta calculates the sum of  S

Now, Yuta has got  2n numbers between  [0,m]. For each  i[0,m], he counts the number of  is he got as  Bi.

Yuta shows Rikka the array  Bi and he wants Rikka to restore  A1An.

It is too difficult for Rikka. Can you help her?  
 

Input
The first line contains a number  t(1t70), the number of the testcases. 

For each testcase, the first line contains two numbers  n,m(1n50,1m104).

The second line contains  m+1 numbers  B0Bm(0Bi2n).
 

Output
For each testcase, print a single line with  n numbers  A1An.

It is guaranteed that there exists at least one solution. And if there are different solutions, print the lexicographic minimum one.
 

Sample Input
 
   
2 2 3 1 1 1 1 3 3 1 3 3 1
 

Sample Output
 
   
1 2 1 1 1
Hint
In the first sample, $A$ is $[1,2]$. $A$ has four subsets $[],[1],[2],[1,2]$ and the sums of each subset are $0,1,2,3$. So $B=[1,1,1,1]$
 

Source
2017 Multi-University Training Contest - Team 5


题目大意:给你数据的数量,以及数据的总和m,还有给你子集中子集和为0-m的子集数量,询问原始数据,按字典序输出。

分析样例
                 n = 2 ,   m = 3  : 原始数据数量有2个,数据总和为3
                 a0 = 1 , a1 = 1 ,  a2 = 1 ,  a3 = 1 :和为1、2、3、4的子集数量都是1个
               子集的数量是2^n,所以子集数量为4,而和为0、1 、2 、 3、 4的子集分别为1 、1 、1 、1,所以原始数据可以为{1 ,2}


解题思路 :我们知道一个n个元素组成的集合的子集数量是2^n,其中有一个是空集,他的子集和为0,所以a0的值一定为1,而题目中说明了原始数据是正整数,所以不可能出现0,所以要简单很多,不需要考虑0的情况,然后我们开始看 a[i]  数组中第一个不为0的数据,即说明从这里开始有数据,即第一个数据我们可以定为 i,确定了一个 值后我们需要将这个数据可以组成的子集的和值给计算出,这里我们使用的是动态规划,动态方程可以为:dp[i+j]+=dp[i],可以计算出和它和它前面的数据的子集和,然后我们将 a[i]-dp[i], 即和值减去组成的新的和值数量,使用一个循环可以得到每一个原始数据,直到所有的a[i]都被减为0,即数据处理完成。

ac代码:
#include 
#include 
#include 
#include 
using namespace std;
#define ll long long
ll a[20005],dp[20005],s[100];//这里需要定义为2倍,不然会内存不够,出现runtime 
int main()
{
	int T,n,m,i,j;
	int sum;
	scanf("%d", &T);
	while(T--)
	{
		sum=0;
		scanf("%d%d",&n,&m);
		for(i=0;i<=m;i++)
		 scanf("%lld",&a[i]);
		 memset(dp,0,sizeof(dp));
		 dp[0]=1;
		for(i=1;i<=m;i++)
		{
			while(a[i]-dp[i])//要将每一个a[i]都减为0 
			{
				s[sum++]=i;//每次都需要赋值为i,知道a[i]减为0 
				for(j=m;j>=0;j--)//计算出和i有关的所有子集和的数量 
				  dp[i+j]+=dp[j];
			}
		}
		printf("%lld",s[0]);
		for(i=1;i

题目链接;点击打开链接http://acm.hdu.edu.cn/showproblem.php?pid=6092
 

你可能感兴趣的:(动态规划,杭电随笔)