Rikka with Subset
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
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 i s 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?
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 i s 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) .
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.
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 1HintIn 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
题目大意
给你两个数n,m,n代表A数列中元素数,m代表As数列中所有数相加的和。接下来给出一个数列B={B0,B1,B2,……,Bm},其中Bi代表A的所有子集中和为i的子集有Bi个。要求,还原A数列,如果有多组结果,按字典序输出最小的一组。
先附上官方题解
签到题,大致的思想就是反过来的背包。
题目分析
现在我们有A集合所有元素的和,还有A的所有子集的和。因为Ai>0,所以一定有B0=1,代表空集的和。如果B1 != 0,那么A集合中一定有B1个元素1,显而易见,因为没有比1更小的数能够相加组成1。如果B1~B(u-1)都等于0,那么第一个不为0的Bu,表示A中有Bu个元素u,同样因为没有更小的元素能相加得到u。接下来,我们需要从下标比u大的所有Bi中将有u参与组成的子集减掉,即b[i] -= b[i-u](u<i<=m),简单解释一下,现在我们要减掉有u参与组成的和为i的子集,也就是需要知道除u外(i-u)还有多少种子集组合方式,也就是B(i-u)。这里要注意一点,因为集合A中可能包含有多个元素u,虽然每个元素u数值相同,但是它们都可以独立地参与到子集地组合中,所以我们要把u逐个减掉。
代码
题目大意
给你两个数n,m,n代表A数列中元素数,m代表As数列中所有数相加的和。接下来给出一个数列B={B0,B1,B2,……,Bm},其中Bi代表A的所有子集中和为i的子集有Bi个。要求,还原A数列,如果有多组结果,按字典序输出最小的一组。
先附上官方题解
签到题,大致的思想就是反过来的背包。
如果 Bi是B 数组中除了 B0 以外第一个值不为 0 的位置,那么显然 i 就是A 中的最小数。
现在需要求出删掉 i 后的B 数组,过程大概是反向的背包,即从小到大让 Bj−=Bj−i。
时间复杂度 O(nm)。
题目分析
现在我们有A集合所有元素的和,还有A的所有子集的和。因为Ai>0,所以一定有B0=1,代表空集的和。如果B1 != 0,那么A集合中一定有B1个元素1,显而易见,因为没有比1更小的数能够相加组成1。如果B1~B(u-1)都等于0,那么第一个不为0的Bu,表示A中有Bu个元素u,同样因为没有更小的元素能相加得到u。接下来,我们需要从下标比u大的所有Bi中将有u参与组成的子集减掉,即b[i] -= b[i-u](u<i<=m),简单解释一下,现在我们要减掉有u参与组成的和为i的子集,也就是需要知道除u外(i-u)还有多少种子集组合方式,也就是B(i-u)。这里要注意一点,因为集合A中可能包含有多个元素u,虽然每个元素u数值相同,但是它们都可以独立地参与到子集地组合中,所以我们要把u逐个减掉。
代码
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long ll;
int T, n, m;
int a[10005];//a[55]//存已经还原的a集合的元素
ll b[10005];
int i, j, k;
int main()
{
//freopen("1008in.txt", "r", stdin);
//freopen("1008out1.txt", "w", stdout);
scanf ("%d",&T);
while (T--)
{
memset (a, 0, sizeof(a));
memset (b, 0, sizeof(b));
scanf ("%d %d",&n,&m);
for (i=0; i<=m; ++i)
{
scanf ("%lld",&b[i]);
}
for (i=1; i<=m; ++i)
{
if (b[i])
{
a[i] = b[i];
for (j=b[i]; j>0; --j)
{
b[i]--;
for (k=i+1; k<=m; ++k)
{
b[k] -= b[k-i];
}
}
}
}
int flag = 1;
for (i=1; i<=m; ++i)
{
if (a[i])
{
for (j=a[i]; j>=1; --j)
{
if (flag)
{
printf ("%d",i);
flag = 0;
}
else
printf (" %d",i);
}
}
}
printf ("\n");
}
return 0;
}