soj 3531 Number Pyramids(观察组合数 + 每种物品至少选一个的完全背包)

来源:互联网 发布:c语言输入函数 编辑:程序博客网 时间:2024/06/05 19:46

题意
给你一个类似杨辉三角的堆积法,问在给定顶端的数和,底部长度的情况下,一共有多少种堆积方式?
分析
这个拿到找了半天分解子问题,记忆化搜索都没有办法…最后才发现了最底部的数,会被扩大,然后传递到顶部去,然后观察这个扩大倍数或发现恰恰是组合数!
假设最底部的数是:a[1],a[2],....a[n]那么最上面的数就是

C0n1a[1]+C1n1a[2]+.....+Cnn1a[n]

然后就把这些组合数当做物品,他们的系数a[i]当做选择的物品的个数来做完全背包就可以了.
然后这里比较特殊的是,每种物品都要至少选择一个,我们就先把背包总容量减去每个物品选一个所需要消耗的容量(i=1...na[i]),剩下的容量再来做完全背包.定义dp[i]为要达到这个容量有多少种选择方式,显然dp[i]+=dp[iCin],


#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>#include <set>using namespace std;const int mod = 1e9 + 9, maxn = 1e6 +9;int n, m;int dp[maxn];int main(void) {    while (~scanf("%d%d", &n, &m)) {        if (n > 20) {            puts("0");            continue;        }        int x = 1 << (n - 1), y = n - 1;        if (x > m) {            puts("0");            continue;        }        int c = 1;        for (int i = 0; i <= y; i++) {            m -= c;            c = c * (y - i) / (i + 1);        }        fill(dp, dp + m + 9, 0);        dp[0] = 1;        for (int i = 0, c = 1; i <= y; i++) {            for (int j = c; j <= m; j++) {                dp[j] = (dp[j] + dp[j - c]) % mod;            }            c = c * (y - i) / (i + 1);        }        printf("%d\n", dp[m] % mod);    }    return 0;}

3 0
原创粉丝点击