hdu 3037 插板法组合 + lucas定理

来源:互联网 发布:大数据图标 编辑:程序博客网 时间:2024/06/09 14:23

分析:

插板法解决的问题:

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;}
0 0