HDU 6092 Rikka with Subset【多重背包+贪心】

来源:互联网 发布:php好学还是java好学 编辑:程序博客网 时间:2024/05/17 02:53

题目链接

题意:A[1]到A[n]这n个正数,和为m。他们的子集的和显然在[0,m]这个范围,B[i]表示和为i的子集的个数。已知B[0]到B[m],求A这个序列字典树最小的情况。

dp[i]表示到目前为止和为i的子集的个数,cnt[i]表示A中i的个数。cnt[i]=B[i]-dp[i],再加上dp[k]+=dp[k-i]表示从dp[k-i]这个和的状态递推到dp[k]这个和的状态,可以理解为多重背包。

#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#include <string>#include <cmath>#include <vector>#include <queue>#include <set>#include <map>using namespace std;#define ll long longconst int maxn=10000+10;int T;int n,m;int b[maxn];int dp[maxn];int cnt[maxn];int a[maxn];int tot=0;int main(){    scanf("%d",&T);    while (T--){        memset(dp,0,sizeof(dp));        memset(cnt,0,sizeof(cnt));        tot=0;        scanf("%d %d",&n,&m);        for (int i=0;i<=m;i++){            scanf("%d",&b[i]);        }        dp[0]=1;        for (int i=1;i<=m;i++){            cnt[i]=b[i]-dp[i];            for (int j=0;j<cnt[i];j++){                a[++tot]=i;                for (int k=m;k>=i;k--){                    dp[k]+=dp[k-i];                }            }        }        for (int i=1;i<=tot;i++){            if (i==1){                printf("%d",a[i]);            }            else{                printf(" %d",a[i]);            }        }        putchar('\n');    }}