1. 程式人生 > >Rikka with Subset HDU - 6092 (DP+組合數)

Rikka with Subset HDU - 6092 (DP+組合數)

namespace col calculate tint 組合數 XML res while restore

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 A1AnA1−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 A1AnA1−An.

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

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


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

The second line contains m+1m+1 numbers B0Bm(0Bi2n)B0−Bm(0≤Bi≤2n).
OutputFor each testcase, print a single line with nn numbers A1AnA1−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]$

        
 

題意:一個含有n個數的數組,他們的sum和是m,並且這n個數的所有子集的sum和的個數用一個數組b來表示。
其中b[i] 表示 子集中sum和為i的有b[i]個。現在給你N,M,b數組,讓你推出數組a,並輸出字典序最小的那一個。

思路:可以知道滿足條件的只有一個數集set,所以只需要排序輸出就是字典序最小的那個了。
那麽如何求數組a呢?,首先我們應該知道,如果有n個0,會產生2^n個sum和為0的集合。
那麽數組a中0的數量直接就是log2(b[0])了。
而sum和為1的只需要用所以的sum和為0的集合加上一個1即可,
所以num[1] = b[1]/b[0];
然後定義數組dp[i],表示不用數字i,僅用小於i中的數湊出來sum和為i的集合數量。
那麽(b[i]-dp[i])/b[0] 就是Num[i]
求dp[i]的過程中用到dp的思想,細節見代碼。
    if (dp[j] == 0) continue;
    if (num[i] == 0) break;

這步的代碼可以節省時間復雜度。

code:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <vector>
#include <iomanip>
#define ALL(x) (x).begin(), (x).end()
#define rt return
#define dll(x) scanf("%I64d",&x)
#define xll(x) printf("%I64d\n",x)
#define sz(a) int(a.size())
#define all(a) a.begin(), a.end()
#define rep(i,x,n) for(int i=x;i<n;i++)
#define repd(i,x,n) for(int i=x;i<=n;i++)
#define pii pair<int,int>
#define pll pair<long long ,long long>
#define gbtb ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define MS0(X) memset((X), 0, sizeof((X)))
#define MSC0(X) memset((X), ‘\0‘, sizeof((X)))
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define eps 1e-6
#define gg(x) getInt(&x)
#define db(x) cout<<"== [ "<<x<<" ] =="<<endl;
using namespace std;
typedef long long ll;
ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
ll lcm(ll a, ll b) {return a / gcd(a, b) * b;}
ll powmod(ll a, ll b, ll MOD) {ll ans = 1; while (b) {if (b % 2)ans = ans * a % MOD; a = a * a % MOD; b /= 2;} return ans;}
inline void getInt(int* p);
const int maxn = 100010;
const int inf = 0x3f3f3f3f;
/*** TEMPLATE CODE * * STARTS HERE ***/
int t;
int n, m;
ll b[maxn];
int dp[maxn];
int num[maxn];
int c(int n, int m)
{
    int sum = 1;
    for (int i = n - m + 1; i <= n; i++) sum *= i;
    for (int i = 1; i <= m; i++) sum /= i;
    return sum;
}
int main()
{
    //freopen("D:\\common_text\\code_stream\\in.txt","r",stdin);
    //freopen("D:\\common_text\\code_stream\\out.txt","w",stdout);
    // gbtb;
    // cin >> t;
    scanf("%d", &t);
    while (t--)
    {
        MS0(num);
        MS0(dp);
        scanf("%d%d", &n, &m);
        repd(i, 0, m)
        {
            scanf("%lld", &b[i]);
            // cin >> b[i];
        }
        num[0] = log2(b[0]);
        num[1] = b[1] / b[0];
        dp[0] = b[0];
        repd(i, 0, m)
        {
            for (int j = m; j >= 0; j--)
            {
                if (dp[j] == 0) continue;
                if (num[i] == 0) break;
                for (int k = 1; k <= num[i]; k++)
                {
                    if (j + k*i <= m)
                    {
                        dp[j + k*i] += dp[j] * c(num[i], k);
                    }
                }
            }
                if (i + 1 <= m)
                {
                    num[i+1]=(b[i+1]-dp[i+1])/b[0];
                }
        }
        bool flag = 0;
        for (int i = 0; i <= m; i++)
        {
            for (int j = 1; j <= num[i]; j++)
            {
                if (!flag) printf("%d", i), flag = 1;
                else printf(" %d", i);
            }
        }
        puts("");
    }



    return 0;
}

inline void getInt(int* p) {
    char ch;
    do {
        ch = getchar();
    } while (ch ==   || ch == \n);
    if (ch == -) {
        *p = -(getchar() - 0);
        while ((ch = getchar()) >= 0 && ch <= 9) {
            *p = *p * 10 - ch + 0;
        }
    }
    else {
        *p = ch - 0;
        while ((ch = getchar()) >= 0 && ch <= 9) {
            *p = *p * 10 + ch - 0;
        }
    }
}





Rikka with Subset HDU - 6092 (DP+組合數)