卡特兰数

定义:长度为n,且由0和1组成的字符串,满足任意前缀中0的个数不小于1的个数的方法数。
公式:

经典问题
火车进出站的方案数(这道题由于数据范围过大,用了质因子分解的方法,本质是卡特兰数)

  1. // 卡特兰数:C(2n, n) / (n + 1)
  2. #include<cstdio>
  3. #include<cstring>
  4. using namespace std;
  5. typedef long long int64;
  6. const int N = 6000000, M = 1e9;
  7. int64 a[N];
  8. int tt = 0;
  9. bool st[60010 * 2];
  10. int p[60010 * 2];
  11. void out() {
  12. for(int i = tt - 1; i >= 0; i--) {
  13. if(i == tt - 1) {
  14. printf("%lld", a[i]);
  15. }
  16. else {
  17. printf("%09lld", a[i]);
  18. }
  19. }
  20. printf("\n");
  21. }
  22. void multi(int prime) {
  23. int64 t = 0;
  24. for(int i = 0; i < tt; i++) {
  25. t += a[i] * prime;
  26. a[i] = t % M;
  27. t /= M;
  28. }
  29. while(t) {
  30. a[tt++] = t % M;
  31. t /= M;
  32. }
  33. }
  34. int get(int64 num, int prime) {
  35. int ans = 0;
  36. while(num) {
  37. ans += num / prime;
  38. num /= prime;
  39. }
  40. return ans;
  41. }
  42. int main() {
  43. memset(st, 0, sizeof st);
  44. memset(p, 0, sizeof p);
  45. memset(a, 0, sizeof a);
  46. int n;
  47. scanf("%d", &n);
  48. for(int i = 2; i <= 2 * n; i ++) {
  49. if(st[i]) {
  50. continue;
  51. }
  52. for(int j = i * 2; j <= 2 * n; j += i) {
  53. st[j] = true;
  54. }
  55. }
  56. for(int i = 2; i <= 2 * n; i++) {
  57. if(!st[i]) {
  58. p[i] = get(2 * n, i) - get(n, i) * 2;
  59. }
  60. }
  61. int k = n + 1;
  62. for(int i = 2; i <= k; i++) {
  63. if(!st[i]) {
  64. while(k % i == 0) {
  65. k /= i;
  66. p[i]--;
  67. }
  68. }
  69. }
  70. a[tt++] = 1;
  71. for(int i = 2; i <= 2 * n; i++) {
  72. //if(p[i]) printf("p[%d]: %d\n", i, p[i]);
  73. while(p[i]) {
  74. multi(i);
  75. p[i]--;
  76. }
  77. }
  78. out();
  79. return 0;
  80. }