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?
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) .
It is guaranteed that there exists at least one solution. And if there are different solutions, print the lexicographic minimum one.
2 2 3 1 1 1 1 3 3 1 3 3 1
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]$
题意:一共有T组测试样例,然后n和m,有m+1个数代表B数列,表示为A数列子集的和为i的有多少种;
解题思路:很多个较小的数字随机组合会求出多个很大的数字,所以从B0向Bm推导,在每求出A序列的一部分这个过程中,更新后续的B序列,更新完的B[i]就是 i 在A序列中出现的次数。
分析完后,主要的难点就是怎么去让已求出来的A序列随机组合,更新后续的B序列直接减就可以了。看成01背包问题,让m为背包去装 i,初始值为dp[0] = 1,由于i依次增大,A子集随机组合不会重复
#include <iostream> #include <cstdio> #include <cstring> using namespace std; typedef long long ll; int n,m; int ans[10005],tmp[10005],dp[10005]; int da[10005]; int main() { int T; scanf("%d",&T); while(T--) { scanf("%d %d",&n,&m); for(int i=0;i<=m;i++) scanf("%d",&da[i]); memset(dp,0,sizeof(dp)); memset(ans,0,sizeof(ans)); memset(tmp,0,sizeof(tmp)); dp[0]=1; int p=0; for(int i=1;i<=m;i++) { tmp[i]=da[i]-dp[i]; for(int j=0;j<tmp[i];j++) { ans[p]=i; p++; for(int k=m;k>=i;k--) { dp[k]+=dp[k-i];//和为k的子集不断更新 } } } for(int i=0;i<n-1;i++) printf("%d ",ans[i]); printf("%d\n",ans[n-1]); } return 0; }