1. 程式人生 > >hdu 6092 Rikka with Subset (集合計數,01背包)

hdu 6092 Rikka with Subset (集合計數,01背包)

restore tdi [0 print set ace each rst col

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(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 B0?Bm(0Bi2n).
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 假設現在有一個元素個數為n的允許有重復元素的集合a,那麽這個a的子集就有2^n個子集,現在給你這2^n個子集的每一個的和(cnt[i]表示子集的和為i的子集個數),讓你還原a集合 第2個樣例意思為子集的和為0 1 2 3 的子集個數分別有1 3 3 1個,原集合a一共有3個元素 思路: 首先我們發現原集合中0的個數是好求的,2^num[0]=cnt[0].那麽怎樣求剩下的元素呢? 發現如果我們一個一個從小到大求,開一個數組sum[i]表示求到當前位置之前子集和為i的子集個數. 有 num[i]*sum[0]+sum[i]=cnt[i],也就是說一共和為i的子集個數等於集合中數字i的個數乘和為0的子集個數再加上之前那些由>0&&<i的元素構成的子集中和為i的個數 然後我們每次求出一個num[i]後,用完全背包的思想將這num[i]個i一個一個的加入到集合中,用完全背包的思想更新sum數組就行了 代碼如下:
 1 #include <bits/stdc++.h>
 2 
 3 using namespace std;
 4 typedef long long ll;
 5 const int maxn = 5e5+500;
 6 int n,m;
 7 ll cnt[maxn];
 8 ll sum[maxn];
 9 int num[maxn];
10 int main()
11 {
12     //freopen("de.txt","r",stdin);
13     int T;
14     scanf("%d",&T);
15     while (T--){
16         memset(sum,0,sizeof sum);
17         memset(num,0,sizeof num);
18         scanf("%d%d",&n,&m);
19         for (int i=0;i<=m;++i)
20             scanf("%lld",&cnt[i]);
21         num[0]=0;
22         sum[0]=cnt[0];
23         while((1<<num[0])<cnt[0]) num[0]++;
24         for (int i=1;i<=m;++i){
25             num[i]=(cnt[i]-sum[i])/sum[0];//num[i]*sum[0]+sum[i]=cnt[i]
26             for (int j=1;j<=num[i];++j){//一個一個的加入幾個
27                 for (int k=m;k>=i;--k){//完全背包思想更新sum
28                     sum[k]+=sum[k-i];
29                 }
30             }
31         }
32         vector<int> vec;
33         for (int i=0;i<=m;++i){
34             for (int j=0;j<num[i];++j)
35                 vec.push_back(i);
36         }
37         for (int i=0;i<vec.size();++i)
38             printf("%d%c",vec[i],i==(vec.size()-1)?\n: );
39     }
40     return 0;
41 }

hdu 6092 Rikka with Subset (集合計數,01背包)