题意:
让你求一个长度为n的数组,这个数组的每个子集的和为a,a的范围为0~m,,
现在给你0~m中每个数出现的次数。求出这个长度为n的数组。
思路:
先求出数组中有几个0,发现0的个数为log(0出现的次数),那么1的个数就为 1出现的次数/0出现的次数 然后根据1的个数,来更新能凑出和为1~m的个数,记dp[i]为已知的数能凑出多少个和为i的数,每得到一个数,就更新一次dp数组,因为为01背包,所以倒序更新。那么2的个数就为 (2出现的次数-dp[2])/0出现的次数,以此类推。
代码:
#include <bits/stdc++.h>
using namespace std;
int ans[50];
int arr[10004];
int n,m;
int dp[10004];
int cnt;
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
cnt = 0;
memset(dp,0,sizeof(dp));
scanf("%d%d",&n,&m);
for(int i = 0;i<=m;i++)
scanf("%d",arr+i);
int num = log(arr[0]);
for(int i = 0;i<num;i++)
ans[cnt++] = 0;
dp[0] = arr[0];
for(int i = 1;i<=m;i++)
{
int num = (arr[i]-dp[i])/dp[0];
while(num--)
{
ans[cnt++] = i;
for(int j = m;j>=0;j--)
{
if(j+i<=m)
{
dp[j+i] += dp[j];
}
}
}
}
for(int i = 0;i<cnt;i++)
{
if(i!=cnt-1)
printf("%d ",ans[i]);
else
printf("%d\n",ans[i]);
}
}
return 0;
}