• 卡特兰数(高精度乘法压位)


    889. 满足条件的01序列

    给定 n

    个 0 和 n 个 1,它们将按照某种顺序排成长度为 2n 的序列,求它们能排列成的所有序列中,能够满足任意前缀序列中 0 的个数都不少于 1

    的个数的序列有多少个。

    输出的答案对 109+7

    取模。

    输入格式

    共一行,包含整数 n

    输出格式

    共一行,包含一个整数,表示答案。

    数据范围

    1≤n≤105

    输入样例:

    3
    

    输出样例:

    5
    

    * 假定在一个二维矩阵的地图里,向右走为0,向上走为1,则要求能排列成的所有序列中,
     * 能够满足任意前缀序列中 0 的个数都不少于 1 的个数的序列,所有点都满足为或者在
     * (0,0) 到 (n,n) 的直线上或者在下方。只要有点越过直线 y=x+1 ,再到达点(n,n),
     * 则这种排列就是不符合要求的。所以不符合要求的走法一定满足从(0,0) 到 (n-1,n+1) 的
     * 路线关于 y=x+1 对称 (因为(0,0) 到 (n,n+1) 的路线一定是不合法的,并且(n,n)与
     * (n-1,n+1) 关于 y=x+1 对称。)。那么我们只要 C(2*n,n) - C(2*n,n-1) 就是答案。
     *
     * C(2*n,n) - C(2*n,n-1) =C(2*n,n)/(n+1);()
     *
     * 卡特兰数:
     * C(2*n,n) - C(2*n,n-1) =(2*n)! / (n! * n! * (n+1))

    1. /**
    2. * 假定在一个二维矩阵的地图里,向右走为0,向上走为1,则要求能排列成的所有序列中,
    3. * 能够满足任意前缀序列中 0 的个数都不少于 1 的个数的序列,所有点都满足为或者在
    4. * (0,0) 到 (n,n) 的直线上或者在下方。只要有点越过直线 y=x+1 ,再到达点(n,n),
    5. * 则这种排列就是不符合要求的。所以不符合要求的走法一定满足从(0,0) 到 (n-1,n+1) 的
    6. * 路线关于 y=x+1 对称 (因为(0,0) 到 (n,n+1) 的路线一定是不合法的,并且(n,n)与
    7. * (n-1,n+1) 关于 y=x+1 对称。)。那么我们只要 C(2*n,n) - C(2*n,n-1) 就是答案。
    8. *
    9. * C(2*n,n) - C(2*n,n-1) =C(2*n,n)/(n+1);()
    10. *
    11. * 卡特兰数:
    12. * C(2*n,n) - C(2*n,n-1) =(2*n)! / (n! * n! * (n+1))
    13. */
    14. #include
    15. using namespace std;
    16. typedef long long LL;
    17. const int mod=1e9+7,maxn=1e5+10;
    18. int fac[2*maxn],infac[maxn];
    19. int qmi(int a,int b,int p)
    20. {
    21. int res=1;
    22. while(b)
    23. {
    24. if(b&1)
    25. res=(LL)res*a%mod;
    26. a=(LL)a*a%mod;
    27. b>>=1;
    28. }
    29. return res;
    30. }
    31. void init(int n)
    32. {
    33. fac[0] = infac[0] = 1; //初始化
    34. for(int i=1;i<=2*n;++i)
    35. fac[i]=(LL)fac[i-1]*i%mod;
    36. for(int i=1;i<=n;++i)
    37. infac[i]=(LL)infac[i-1]*qmi(i,mod-2,mod)%mod; //必须要用qmi求逆元
    38. }
    39. int main()
    40. {
    41. int n;
    42. cin >> n;
    43. init(n);
    44. cout << (LL)fac[2*n]*infac[n]%mod*infac[n]%mod *qmi(n+1,mod-2,mod)%mod << endl;
    45. return 0;
    46. }

    130. 火车进出栈问题

    一列火车 n

    节车厢,依次编号为 1,2,3,…,n

    每节车厢有两种运动方式,进栈与出栈,问 n

    节车厢出栈的可能排列方式有多少种。

    输入格式

    输入一个整数 n

    ,代表火车的车厢数。

    输出格式

    输出一个整数 s

    表示 n

    节车厢出栈的可能排列方式数量。

    数据范围

    1≤n≤60000

    输入样例:

    3
    

    输出样例:

    5
    

    * 卡特兰数:
     * C(2*n,n) - C(2*n,n-1) =(2*n)! / (n! * n! * (n+1));
     *
     * 这个题与满足条件的01序列解法一样,只不过这个题是输出全部方案数,不取模,
     * 输出高精度数据;由于数据较大,所以我们用质因数分解的方法来求解。
     * 最后由于高精度数据相乘是主要的算法时间消耗,因此我们优化高精度数据相乘,
     * 用LL来存储结果,每次相乘我们以 M=1e9 作为进制数,(这样两个M相乘也不会爆LL);
     * 这样能减少许多乘法步骤;这种方法称为高精度压位。

    1. /**
    2. * 假定在一个二维矩阵的地图里,向右走为0,向上走为1,则要求能排列成的所有序列中,
    3. * 能够满足任意前缀序列中 0 的个数都不少于 1 的个数的序列,所有点都满足为或者在
    4. * (0,0) 到 (n,n) 的直线上或者在下方。只要有点越过直线 y=x+1 ,再到达点(n,n),
    5. * 则这种排列就是不符合要求的。所以不符合要求的走法一定满足从(0,0) 到 (n-1,n+1) 的
    6. * 路线关于 y=x+1 对称 (因为(0,0) 到 (n,n+1) 的路线一定是不合法的,并且(n,n)与
    7. * (n-1,n+1) 关于 y=x+1 对称。)。那么我们只要 C(2*n,n) - C(2*n,n-1) 就是答案。
    8. *
    9. * C(2*n,n) - C(2*n,n-1) =C(2*n,n)/(n+1);()
    10. *
    11. * 卡特兰数:
    12. * C(2*n,n) - C(2*n,n-1) =(2*n)! / (n! * n! * (n+1));
    13. *
    14. * 这个题与满足条件的01序列解法一样,只不过这个题是输出全部方案数,不取模,
    15. * 输出高精度数据;由于数据较大,所以我们用质因数分解的方法来求解。
    16. * 最后由于高精度数据相乘是主要的算法时间消耗,因此我们优化高精度数据相乘,
    17. * 用LL来存储结果,每次相乘我们以 M=1e9 作为进制数,(这样两个M相乘也不会爆LL);
    18. * 这样能减少许多乘法步骤;这种方法称为高精度压位。
    19. */
    20. #include
    21. #include
    22. using namespace std;
    23. typedef long long LL;
    24. const LL M=1e9;
    25. const int N = 12e4+10;
    26. int p[N],sum[N],num=0;
    27. bool hs[N];
    28. void get_primer(int n) //获得n以内的素数
    29. {
    30. for(int i=2;i<=n;++i)
    31. {
    32. if(hs[i]==0)
    33. p[num++]=i;
    34. for(int j=0;p[j]<=n/i;++j)
    35. {
    36. hs[p[j]*i]=1;
    37. if(i%p[j]==0)
    38. break;
    39. }
    40. }
    41. }
    42. int cal(int n,int p) //计算n! 内有多少个因子p
    43. {
    44. int cnt=0;
    45. while (n)
    46. {
    47. cnt+=n/p;
    48. n/=p;
    49. }
    50. return cnt;
    51. }
    52. void get_pow(int a,int b) //将C(a,b) 进行质因子分解
    53. {
    54. for(int i=0;i
    55. {
    56. int cnt=cal(a,p[i]) -cal(b,p[i])*2;
    57. sum[i]=cnt;
    58. }
    59. }
    60. void mul(vector &A,int b) //高精度与整数相乘
    61. {
    62. LL d=0;
    63. for(int i=0;isize();++i)
    64. {
    65. d+=A[i]*b;
    66. A[i]=d%M;
    67. d/=M;
    68. }
    69. while(d)
    70. {
    71. A.push_back(d%M);
    72. d/=M;
    73. }
    74. }
    75. void print(vector &res) //输出高精度数据
    76. {
    77. cout << res.back(); // 最后一位不需要输出九位
    78. for(int i=res.size()-2;i>=0;--i)
    79. printf("%09lld",res[i]); //因为是按着1e9作为进制数,所以中间的位要输出九位,
    80. cout << endl; //不足九位的补零
    81. }
    82. int main()
    83. {
    84. int n;
    85. cin >> n;
    86. get_primer(2*n);
    87. get_pow(2*n,n);
    88. int r=n+1;
    89. for(int i=0;i1;++i)
    90. {
    91. while(r%p[i]==0)
    92. {
    93. sum[i]-=1;
    94. r/=p[i];
    95. }
    96. }
    97. vector res;
    98. res.push_back(1);
    99. for(int i=0;i
    100. for(int j=0;j
    101. mul(res,p[i]);
    102. print(res);
    103. return 0;
    104. }

  • 相关阅读:
    【Java网络原理】 四
    从源码看std::weak_ptr
    postgresql源码学习(51)—— 提交日志CLOG 提交日志CLOG 原理 用途 管理函数
    模型的选择与调优(网格搜索与交叉验证)
    跟艾文学编程《Python基础》(6)numpy数值计算
    Django使用Token认证(simplejwt库的配置)
    河南共享股东系统开发模式介绍
    场景应用:你知道 i = i++;的含义么?
    草图大师SketchUp Pro 2023 for Mac
    数字化开采|AIRIOT智慧矿山自动化生产解决方案
  • 原文地址:https://blog.csdn.net/qq_51825761/article/details/126324971