[关闭]
@Pinetrie 2019-02-21T21:13:33.000000Z 字数 1146 阅读 868

I - Saving Beans HDU - 3037

题意

n个树中取小于等于m个豆子,有多少种取法?

题解

假设n个树中取m个豆子。用隔板法,可以转化为在m个人中插入n-1个人有多少种方法。第一个人可以插入的位置有m+1个,第二个人可以插入的位置有m+2个。那么一共有(m+1)(m+2)...(m+n-1) = C(m+n-1,n-1)(n-1)!。而计算收取豆子时是不考虑树的位置的,计算结果还要除以(n-1)!,因此共有C(n + m - 1,m)种方法。再计算m从0到m,C(n-1,0) + C(n,1) + ...+C(n+m-1,m) = C(n+m,m)。再用lucas定理计算

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. typedef long long ll;
  4. const int maxn = 100010;
  5. ll n,m,p;
  6. ll f[maxn];
  7. void init()
  8. {
  9. f[0] = 1;
  10. for(int i = 1;i <= p;i++)
  11. {
  12. f[i] = f[i - 1] * i % p;
  13. }
  14. }
  15. ll pow_mod(ll a,ll n,ll p)
  16. {
  17. ll res = 1;
  18. while(n)
  19. {
  20. if(n & 1) res = res * a % p;
  21. a = a * a % p;
  22. n >>= 1;
  23. }
  24. return res;
  25. }
  26. ll comb(ll n,ll m)
  27. {
  28. if(n < m) return 0;
  29. return f[n] * pow_mod(f[m] * f[n - m] % p,p - 2,p) % p;
  30. }
  31. ll lucas(ll n,ll m)
  32. {
  33. if(n < m) return 0;
  34. if(m == 0) return 1;
  35. return comb(n % p,m % p) * lucas(n / p,m / p) % p;
  36. }
  37. int main()
  38. {
  39. int T;
  40. scanf("%d",&T);
  41. while(T--)
  42. {
  43. scanf("%lld %lld %lld",&n,&m,&p);
  44. init();
  45. printf("%lld\n",lucas(n + m,m));
  46. }
  47. return 0;
  48. }

J - 小兔的棋盘 HDU - 2067

题解

求不经过对角线的网格路径数,是卡特兰数的模型。既可以在下半部分走,也可以在上半部分走,所以结果要乘2。

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. typedef long long ll;
  4. ll kart[36];
  5. void init()
  6. {
  7. kart[0] = kart[1] = 1;
  8. for(int i = 2;i < 36;i++)
  9. {
  10. for(int j = 0;j < i;j++)
  11. {
  12. kart[i] += kart[j] * kart[i - j - 1];
  13. }
  14. }
  15. }
  16. int main()
  17. {
  18. init();
  19. ll n,cas = 0;
  20. while(scanf("%lld",&n) && n != -1)
  21. {
  22. printf("%lld %lld %lld\n",++cas,n,kart[n] * 2);
  23. }
  24. return 0;
  25. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注