HDU6092-Rikka with Subset(背包)

来源:互联网 发布:网络黄金egd裴蕾抓了吗 编辑:程序博客网 时间:2024/05/23 01:22

Rikka with Subset

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

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 A1−An 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 A1−An.

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

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

For each testcase, the first line contains two numbers n,m(1≤n≤50,1≤m≤104).

The second line contains m+1 numbers B0−Bm(0≤Bi≤2n).

Output
For each testcase, print a single line with n numbers A1−An.

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

Recommend
liuyiding | We have carefully selected several similar problems for you: 6107 6106 6105 6104 6103

题意:

如果有一个序列,有n的数字,那么它的子集就有2^n个,每个子集对应一个和,给定搞这些和,求原序列

可能还是太菜了,当时快结束才想到
可以算出0和1各有多少个,
就可以算出只用01可以得到2的方案数,
减去读入2有的个数,
就是真实2有多少个,
然后用2去更新背包,
就能得到用012能得到多少个3,
用读入3的个数减去用012组成3的个数,
及时真实3有多少个,
以此类推,一直到m。
就求出了符合条件的序列,从0开始一步步算保证了字典序最小

#include<cstdio>#include<cstring>#include<algorithm>#include<cmath>using namespace std;const int maxn=1e4+5;int n,m,cnt[maxn],num[maxn],f[maxn];int main(){  int T;  scanf("%d",&T);  while(T--)  {      scanf("%d%d",&n,&m);      for(int i=0;i<=m;++i)scanf("%d",&cnt[i]),num[i]=0,f[i]=0;      num[0]=log2(cnt[0]);      int sum=num[0];      f[0]=1;      for(int i=1;i<=m&&sum<n;++i)      {        num[i]=cnt[i]/cnt[0]-f[i];        for(int j=1;j<=num[i];++j)          for(int v=m;v>=i;--v)            f[v]+=f[v-i];        if(num[i]>0)sum+=num[i];        //if(num[i]<0)printf("-1\n");      }      int tot=0;      for(int i=0;i<=m&&tot<n;++i)      if(num[i])    {        while(num[i]&&tot<n)        {            tot++;            num[i]--;          if(tot!=n)printf("%d ",i);          else printf("%d",i);        }        if(tot==n)break;      }      printf("\n");  }  return 0;}
原创粉丝点击