1. 程式人生 > >hdu 3037 插板法組合 + lucas定理

hdu 3037 插板法組合 + lucas定理

分析:

插板法解決的問題:

a1+a2+a3+.....+an=m
如果ai必須是正整數,Cn1m1
如果ai是非負數,先強制選1轉化為正整數Cn1m1+n
擴充套件,對於每個數最小為多少都可以通過先強行加減的方法把它轉化為,正整數問題。
lucas定理:解決Cmn%mod的計算。
本題就是插板法列出求和公式,用組合數的性質化簡求和公式,最後算Cmn+m
#include <cstdio>
#include <cstring>
#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std; #define pr(x) cout << #x << ": " << x << " " #define pl(x) cout << #x << ": " << x << endl; struct jibancanyang { int n, m, mod; int fac[int(1e5) + 7]; //定義範圍為mod的範圍! void init() { fac[0] = 1; for (int
i = 1; i <= mod; ++i) fac[i] = (long long)fac[i - 1] * i % mod; } long long fastpow(long long a, long long b) { long long x = a % mod, ret = 1; while (b) { if (b & 1) ret = ret * x % mod; x = x * x % mod; b >>= 1; } return
ret; } int C(int n, int m, int mod) { return m > n ? 0 : fac[n] * fastpow((long long)fac[m] * fac[n - m], mod - 2) % mod; } int lucas(long long n, long long m, int mod) { return m ? (long long)C(n % mod, m % mod, mod) * lucas(n / mod, m / mod, mod) % mod : 1; } void fun() { int T; scanf("%d", &T); while (T--) { cin >> n >> m >> mod; init(); cout << lucas(n + m, m, mod) << endl;; } } }ac; int main() { #ifdef LOCAL freopen("in.txt", "r", stdin); //freopen("out.txt", "w", stdout); #endif ac.fun(); return 0; }