1. 程式人生 > >lightoj 1226 - One Unit Machine(dp+大組合數去摸)

lightoj 1226 - One Unit Machine(dp+大組合數去摸)

style mes tdi clas tar 方程式 ons target ase

題目鏈接: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+大組合數去摸)