AcWing 火车进出栈问题

AcWing 火车进出栈问题

Description

  • 一列火车n节车厢,依次编号为1,2,3,…,n。

    每节车厢有两种运动方式,进栈与出栈,问n节车厢出栈的可能排列方式有多少种。

Input

  • 输入一个整数n,代表火车的车厢数。

Output

  • 输出一个整数s表示n节车厢出栈的可能排列方式数量。

Data Size

  • 1≤n≤60000

Sample Input

3

Sample Output

5

题解:

  • 用卡特兰数切了,证明如下:

设dp[i]为有i个数时的方案数。设x为最后出栈的一个元素,则已经出栈的元素中比x大的元素个数为n-x个,比x小的元素个数为x-1个。那么每部分的方案数分别为dp[n - x]、dp[x - 1]。因为它们两部分互相影响,是一个乘法原理。那么当i=n时,dp[n] = ?因为x可以在1到n中取值,所以总的方案数dp[n] = dp[0] * dp[n - 1] + dp[1] * dp[n - 2] + ...dp[n - 1] * dp[0]。那么这恰好就是卡特兰数的递推式。

//因为反正是卡特兰的裸题,高精度又懒(不会)写
//所以嫖了一遍题解上来
//原作者:秦淮岸灯火阑珊大大
#include <iostream>
#include <cstdio>
#define fir(i,a,b) for(int i=a;i<=b;i++)
#define ll long long
using namespace std;

const ll M=1e9;//M为压位的最大值
ll a[60004],l,sum[120004];
int n;

void Prime(int b,int f)
{
    for(int j=2;j*j<=b && b!=1;j++)//质因数分解.
        while(b%j==0)
            sum[j]+=f, b/=j;
    if(b) sum[b]+=f;
}
void High(ll c)
{
    for(int i=1;i<=l;i++) a[i]*=c;
    for(int i=1;i<=l;i++)
        a[i+1]+=a[i]/M,a[i]%=M;//我们需要压缩位置快速处理
    while(a[l+1]) ++l;
}
int main()
{
    a[1]=1,l=1;
    scanf("%d",&n);
    //对于两个组合数相除,我们这道题目必须使用快速的质因数分解法,去处理.
    for(int i=1;i<=n;i++) Prime(n+i,1);
    for(int i=2;i<=n+1;i++) Prime(i,-1);
    for(int i=2;i<=2*n;i++)
        for(ll j=0;j<sum[i];++j) 
            High(i);//高精度
    printf("%lld",a[l]);
    for(ll i=l-1;i;--i) 
        printf("%09lld",a[i]);//输出
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/BigYellowDog/p/11300737.html