HDU6092——Rikka with Subset 【dp】

题目网址:

https://vjudge.net/problem/HDU-6092

As we know, Rikka is poor at math. Yuta is worrying about this situation, so he gives Rikka some math tasks to practice. There is one of them: 

Yuta has nn positive A1−AnA1−An and their sum is mm. Then for each subset SS of AA, Yuta calculates the sum of SS. 

Now, Yuta has got 2n2n numbers between [0,m][0,m]. For each i∈[0,m]i∈[0,m], he counts the number of iis he got as BiBi. 

Yuta shows Rikka the array BiBi and he wants Rikka to restore A1−AnA1−An. 

It is too difficult for Rikka. Can you help her?  

Input

The first line contains a number t(1≤t≤70)t(1≤t≤70), the number of the testcases. 

For each testcase, the first line contains two numbers n,m(1≤n≤50,1≤m≤104)n,m(1≤n≤50,1≤m≤104).

The second line contains m+1m+1 numbers B0−Bm(0≤Bi≤2n)B0−Bm(0≤Bi≤2n).

Output

For each testcase, print a single line with nn numbers A1−AnA1−An. 

It is guaranteed that there exists at least one solution. And if there are different solutions, print the lexicographic minimum one.

Sample Input

2
2 3
1 1 1 1
3 3
1 3 3 1

Sample Output

1 2
1 1 1

        
  

Hint

In 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]$

解题思路:

用dp[j]来表示组成 j 所需的方案数,那么对于数 i 来说,数 i 的个数就是子序列中和为 i 的个数即 b[i] 减去其他数字组成 i 的个数即 dp[i],由此可以算出数字 i 的个数。

由于dp[j]来表示组成 j 所需的方案数,那么对于dp[j]来说,dp[j] = dp[j] + dp[j-i]

因此我们可以先遍历要确定的数字即最外层的循环 for(ll i=1;i<=m;i++),再确定数字 i 的个数,内两层循环相当于一个01背包,以确定更新dp数组

代码:

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstdlib>
#include <cstring>
#include <map>
#include <stack>
#include <queue>
#include <vector>
#include <bitset>
#include <set>
#include <utility>
#include <sstream>
#include <iomanip>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define inf 0x3f3f3f3f
#define rep(i,l,r) for(int i=l;i<=r;i++)
#define lep(i,l,r) for(int i=l;i>=r;i--)
#define ms(arr) memset(arr,0,sizeof(arr))
//priority_queue<int,vector<int> ,greater<int> >q;
const int maxn = (int)1e5 + 5;
const ll mod = 1e9+7;
ll a[120];
ll dp[10100];
ll b[10020];
int main() 
{
    #ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
    #endif
    //freopen("out.txt", "w", stdout);
    ios::sync_with_stdio(0),cin.tie(0);
    int t;
    scanf("%d",&t);
    while(t--) {
    	ms(dp);
    	int n,m;
    	scanf("%d %d",&n,&m);
    	rep(i,0,m) scanf("%I64d",&b[i]);
    	dp[0]=1;
    	int cnt=0;
    	for(ll i=1;i<=m;i++) {
    		if(b[i]) {
    			if(cnt==n) break;
    			ll num=b[i]-dp[i];
    			for(ll j=1;j<=num;j++) {
    				a[++cnt]=i;
    				for(ll k=m;k>=i;k--) {
    					dp[k]=dp[k]+dp[k-i];
    				}
    			}
    		}
    	}
    	for(int i=1;i<cnt;i++) {
    		printf("%I64d ",a[i]);
    	}
    	printf("%I64d\n",a[cnt]);
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值