HDU - 3037 Saving Beans
阿新 • • 發佈:2018-12-13
題目大意:將不大於m個種子隨機放在n個樹上,有多少種可能的結果資料量可能有點大,結果模一個素數p
/*
插板法:將N個物品分成M組,每一組至少有一件物品,這個問題就能轉換成N個物品擺在桌子上,然後中間有N-1個空,在這N-1個空裡面找M個位置,把板子插進去
*/
/*
但是本題劃分的組裡面有含有的板子為0的情況所以 每一種的情況為 C(n+i-1, i)
組合數的遞推公式: C(n, m) = C(n-1, m-1) + C(n-1, m);
本題的要求是求出來不大於m的所有可能情況:
那麼m 可能為0, 1, 2, ... , m
所以總的答案 = C(n-1, 0) + C(n, 1) + C(n+1, 2) + C(n+2, 3) + ... + C(n+m-1, m) //迭代累加
= C(n+m, m)
*/
AcCode:
//Lacus 求大組合數取餘數問題 C(n, m) % p, p一定為素數 //並且p最大為 10^5, m, n可以超級大 #include<iostream> #include<cstdio> #include<cstring> #include<cmath> using namespace std; const int maxn = 100010; typedef long long LL; LL factorial[maxn]; LL pow_mod(LL a, LL b, LL p) { LL ans = 1; LL base = a; while(b){ if(b & 1) ans = (base*ans) % p; base = (base*base) % p; b >>= 1; } return ans; } void init(LL p) { factorial[0] = 1; for(int i = 1; i <= p; i++) factorial[i] = (factorial[i-1]*i) % p; return ; } LL Lucas(LL n, LL m, LL p) { LL ans = 1; while(n && m){ LL aa = n % p, bb = m % p; if(aa < bb) return 0; ans = ans * factorial[aa] * pow_mod(factorial[bb]*factorial[aa-bb]%p, p-2, p) % p; n /= p, m /= p; } return ans; } int main() { int T; LL n, m, p; scanf("%d", &T); while(T--){ scanf("%lld %lld %lld", &n, &m, &p); init(p); LL ans = Lucas(m+n, m, p); cout << ans << endl; } return 0; }