lightoj 1226 - One Unit Machine(dp+大组合数去摸)

Posted Gealo

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了lightoj 1226 - One Unit Machine(dp+大组合数去摸)相关的知识,希望对你有一定的参考价值。

题目链接: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\n" , ++Case , dp[1]);
    }
    return 0;
}

 

以上是关于lightoj 1226 - One Unit Machine(dp+大组合数去摸)的主要内容,如果未能解决你的问题,请参考以下文章

UNIT ONE

LightOJ1191 Bar Codes(DP)

lightoj 1248-G - Dice (III) (概率dp)

阶乘质因子分解——lightoj1035

LightOJ1158 Anagram Division(状压DP)

LightOJ - 1370 Bi-shoe and Phi-shoe