2 1 2 5 2 1 5
3 3HintHint For sample 1, squirrels will put no more than 2 beans in one tree. Since trees are different, we can label them as 1, 2 … and so on. The 3 ways are: put no beans, put 1 bean in tree 1 and put 2 beans in tree 1. For sample 2, the 3 ways are: put no beans, put 1 bean in tree 1 and put 1 bean in tree 2.
分析:首先是不大于m颗种子,我没可以认为少于m的那些种子存放在了第n+1颗树上,这样的话,问题就转化成了将m颗种子存放在n+1颗树上的方案数。ok这个是组合数学里面的公式,亦即插板法,也就是X1+X2+X3+……+Xn+1 = m;so,答案是C(n+m,m)。然后就是基础的费马小定理求逆元(当然也可以用扩展欧几里德算法求逆元,然而我才刚开始学数论,并不会 - -),Lucas定理求解了。
费马小定理不懂的点这里;
扩展欧几里德算法可以点这里;
Lucas定理不懂的点这里。
#include <iostream> #include <cstdio> #include <cstring> #include <stack> #include <queue> #include <map> #include <set> #include <vector> #include <cmath> #include <algorithm> using namespace std; const double eps = 1e-6; const double pi = acos(-1.0); const int INF = 0x3f3f3f3f; const int MOD = 1000000007; #define ll long long #define CL(a) memset(a,0,sizeof(a)) ll f[100010]; ll init(ll p)//求阶乘,用于计算组合数 { f[0]=1; for (int i=1; i<=p ;i++) f[i] = f[i-1]*i%p; } ll mod_pow(int a, int n, int p)//这里求的是a^n,也就是(f[bb]*f[aa-bb]%p)^(p-2) { ll aa = a,re = 1; while (n) { if (n&1) re=(re*aa)%p; aa=(aa*aa)%p; n>>=1; } return re; } ll Lucas(ll a, ll b, ll p)//Lucas定理 { ll re=1; while (a && b) { ll aa=a%p,bb=b%p; if (aa < bb) return 0; re =re*f[aa]*mod_pow(f[bb]*f[aa-bb]%p, p-2, p)%p;//费马小定理求逆元 a /= p; b /= p; } return re; } int main () { int T; ll n,m,p; cin>>T; while (T--) { cin>>n>>m>>p; init(p); cout<<Lucas(n+m, m, p)<<endl; } return 0; }