火车进出栈问题 卡特兰数

问题 B: 火车进出栈问题

时间限制: 1 Sec  内存限制: 128 MB
提交: 41  解决: 9
[提交] [状态] [讨论版] [命题人:admin]

题目描述

一列火车n节车厢,依次编号为1,2,3,…,n。每节车厢有两种运动方式,进栈与出栈,问n节车厢出栈的可能排列方式有多少种。

 

输入

一个数,n(n<=60000)

 

输出

一个数s表示n节车厢出栈的可能排列方式

 

样例输入

3

 

样例输出

5

 

[提交][状态]

 

典型的卡特兰数例子,但是阶乘要用质因数分解(算术基本定理)来算,不然会T

\frac{1}{n+1}C\binom{n}{2n}  将上下阶乘质因数分解,然后约掉相同的质因数之后再乘,最后再除 n+1

用java写的大数,(纪念第一次完全自己写的java大数)

代码:

import java.math.BigInteger;
import java.util.Scanner;


public class Main {
    static Scanner cin = new Scanner(System.in);
    static final int maxn = 200100;
    static int[] prime = new int[maxn];
    static boolean[] f = new boolean[maxn];
    static int k;
    static void init(){
        for(int i=0; i<maxn; i++)
            f[i] = false;
        f[1] = true;
        k = 0;
        for(int i=2; i<maxn; i++){
            if(f[i] == false)
                prime[k++] = i;
            for(int j=0; j<k & prime[j] * i < maxn; j++){
                f[prime[j]*i] = true;
                if(i % prime[j] == 0)  break;
            }
        }
    }
    static BigInteger qpow(int x,int b){
        BigInteger a = BigInteger.valueOf(x);
        BigInteger ret = BigInteger.valueOf(1);
        while(b != 0){
            if(b%2 == 1)  ret = ret.multiply(a);
            a = a.multiply(a);
            b >>= 1;
        }
        return ret;
    }
    public static void main(String args[]){
        int n;
        n = cin.nextInt();
        init();
        BigInteger ans = BigInteger.valueOf(1);
        int p,v;
        int cnt = 0;
        for(int i=0; i<k && prime[i] <= n*2; i++){
            cnt = 0;
            p = prime[i];
            v = n * 2;
            while(v > 0){
                cnt += v/p;
                v /= p;
            }
            v = n;
            while(v > 0){
                cnt -= v/p * 2;
                v /= p;
            }
            ans = ans.multiply(qpow(p,cnt));
        }
        BigInteger x = BigInteger.valueOf(n+1);
        ans = ans.divide(x);
        System.out.println(ans);
    }
}

如果进栈数n小的话,还可以用卡特兰数的递推公式 C_{n}=C_{0} \times C_{n-1} + C_{1} \times C_{n-2}+\cdots \cdots + C_{n-1}\times C_{0}     

#include <bits/stdc++.h>
using namespace std;
const  int maxn=2e5+10;
#define INF 0x3f3f3f;
const int mod=998244353;
typedef long long ll;
int f[maxn];
int main()
{
    int n;
    cin>>n;
    f[0] = f[1] = 1;
    for(int i=2; i<=n; i++){
        for(int j=0; j<i; j++){
            f[i] += f[j] * f[i-j-1]; 
        }
    }
    cout<<f[n]<<endl;
    return 0;
}

 

转载于:https://www.cnblogs.com/renxiaomiao/p/9642662.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在C语言中,我们可以使用数组或链表来模拟栈(先后出,LIFO)的数据结构,用来模拟火车站和出站的过程。这里是一个简单的链表实现的栈火车出站的示例代码: ```c #include <stdio.h> #include <stdlib.h> // 定义栈节点结构 typedef struct Node { int value; struct Node* next; } StackNode; // 初始化栈 StackNode* createStack() { StackNode* top = (StackNode*)malloc(sizeof(StackNode)); if (top) { top->value = 0; // 初始化栈顶元素 top->next = NULL; } return top; } // 入栈 void push(StackNode** top, int value) { StackNode* newNode = (StackNode*)malloc(sizeof(StackNode)); if (newNode) { newNode->value = value; newNode->next = *top; *top = newNode; } else { printf("Memory allocation failed!\n"); } } // 出栈 int pop(StackNode** top) { if (*top == NULL) { printf("Stack is empty.\n"); return -1; } else { int value = (*top)->value; StackNode* temp = *top; *top = (*top)->next; free(temp); return value; } } // 模拟火车站(入栈) void trainEnter(int trainNumber, StackNode** top) { printf("Train %d entering the station.\n", trainNumber); push(top, trainNumber); } // 模拟火车出站(出栈) void trainLeave(StackNode** top) { int trainNumber = pop(top); if (trainNumber != -1) { printf("Train %d has left the station.\n", trainNumber); } } int main() { StackNode* top = createStack(); // 示例操作 trainEnter(101, &top); trainEnter(202, &top); trainLeave(&top); trainLeave(&top); return 0; } ``` 在这个例子中,我们定义了一个栈结构,并实现了入栈(push)、出栈(pop)以及模拟火车站(trainEnter)和出站(trainLeave)的操作。火车站是将车次压入栈顶,火车出站则是从栈顶取出车次。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值