HDu 3037 Saving Beans(組合せ数学)
4167 ワード
hdu 3037 Saving Beans
n個の数と、mより大きくない場合、結果はpを型抜き、pは素数に保証される.
解題構想:仕切り板法,C(nn+m)多選の一枚はn個数の和がm以下であることを保証した.しかしn,mは大きいのでLucas定理を用いる.
n個の数と、mより大きくない場合、結果はpを型抜き、pは素数に保証される.
解題構想:仕切り板法,C(nn+m)多選の一枚はn個数の和がm以下であることを保証した.しかしn,mは大きいのでLucas定理を用いる.
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
ll n, m, p;
ll qPow (ll a, ll k) {
ll ans = 1;
while (k) {
if (k&1)
ans = (ans * a) % p;
a = (a * a) % p;
k /= 2;
}
return ans;
}
/* long long qPow(long long a, long long k) { if (k == 0) return 1; if (k == 1) return a; long long ans = qPow(a * a % p, k>>1); if (k&1) ans = ans * a % p; return ans; } */
ll C (ll a, ll b) {
if (a < b)
return 0;
if (b > a - b)
b = a - b;
ll up = 1, down = 1;
for (ll i = 0; i < b; i++) {
up = up * (a-i) % p;
down = down * (i+1) % p;
}
return up * qPow(down, p-2) % p;
}
ll lucas (ll a, ll b, ll p) {
if (b == 0)
return 1;
return C(a%p, b%p) * lucas(a/p, b/p, p) % p;
}
int main () {
int cas;
scanf("%d", &cas);
while (cas--) {
scanf("%lld%lld%lld", &n, &m, &p);
printf("%lld
", lucas(n+m, m, p));
}
return 0;
}