hdu6092Rikka with Subset(dp+思维)

来源:互联网 发布:千里眼软件黑屏 编辑:程序博客网 时间:2024/05/22 15:54

题意:

让你求一个长度为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;}