lightoj 1226

题目链接:http://www.lightoj.com/volume_showproblem.php?problem=1226

题解:由于这些任务完成是有先后的所以最后一个完成的肯定是最后一个任务的子任务,不妨设dp[i]表示第几个任务完成后总共有几种方案,这里要逆着来至于为什么想想也是挺好理解的。于是有这么一个方程式dp[i]=dp[i + 1]*C(sum-1,k[i]-1),这样列出来就更好理解了。就是最后一个位置肯定是确定的之后就靠组合来凑。

#include <iostream>
#include <cstring>
#include <cstdio>
#define mod 1000000007
using namespace std;
typedef long long ll;
const int M = 1234;
ll k[M];
ll dp[M] , Po[1234567];
ll mod_pow(ll a , ll b) {
    ll res = 1;
    while(b) {
        if(b & 1) res = (res * a) % mod;
        a = (a * a) % mod;
        b >>= 1;
    }
    return res;
}
ll C(ll n , ll m) {
    if(n < m) return 0;
    if(!m || !n) return 1;
    ll res = (Po[n] * mod_pow(Po[m] * Po[n - m] % mod , mod - 2)) % mod;
    return res;
}
int main() {
    int t , n;
    scanf("%d" , &t);
    int Case = 0;
    Po[0] = 1;
    for(int i = 1 ; i < 1234567 ; i++) {
        Po[i] = Po[i - 1] * i % mod;
        Po[i] %= mod;
    }
    while(t--) {
        memset(dp , 0 , sizeof(dp));
        scanf("%d" , &n);
        ll sum = 0;
        for(int i = 1 ; i <= n ; i++) {
            scanf("%lld" , &k[i]);
            sum += k[i];
        }
        dp[n] = C(sum - 1 , k[n] - 1);
        dp[n] %= mod;
        sum -= k[n];
        for(int i = n - 1 ; i >= 1 ; i--) {
            dp[i] = dp[i + 1] * C(sum - 1 , k[i] - 1) % mod;
            dp[i] %= mod;
            sum -= k[i];
        }
        printf("Case %d: %lld
" , ++Case , dp[1]);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/TnT2333333/p/7656581.html