hdu 6092 Rikka with Subset 01背包 思维

dp[i][j]表示前i个元素,子集和为j的个数。d[i][j] = d[i][j] + d[i-1][j-k] (第i个元素的值为k)。这里可以优化成一维数组

比如序列为 1 2 3,每一步的dp值为

1 0 0 0 0 0 0  (d[0][0]=1)

1 1 0 0 0 0 0

1 1 1 1 0 0 0

1 1 1 2 1 1 1

最终的序列就是题目给出的B序列,把B序列减去每一次dp得到的序列,第一个非0值就是a序列中的值

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#define max_n 10010
using namespace std;
int a[max_n], b[max_n], dp[max_n];
//dp[i]表示:和为i的子集个数

int main()
{
//    freopen("in.txt","r",stdin);
    int t, n, m;
    scanf("%d", &t);
    while(t--)
    {
        memset(dp, 0, sizeof(dp));
        scanf("%d %d", &n, &m);
        for(int i = 0; i <= m; i++)
            scanf("%d", &b[i]);
        dp[0] = 1; //初始化值
        int num = 0;
        for(int i = 1; i <= m; i++)
        {
            int t = b[i] - dp[i];//A序列中值为i的个数
            for(int j = 0; j < t; j++)
            {
                a[num++] = i; //对A序列赋值
                for(int k = m; k>= i; k--)   //处理成01背包
                {
                    dp[k] += dp[k - i]; //计算和为k的A子集个数
                }
            }
        }
        for(int i = 0; i < num; i++)
        {
            if(i > 0) printf(" ");
            printf("%d", a[i]);//输出A序列
        }
        printf("\n");
    }
    return 0;
}

 

posted @ 2017-08-09 10:12  Pacify  阅读(173)  评论(0编辑  收藏  举报