问题 B: 火车进出栈问题
时间限制: 1 Sec 内存限制: 128 MB
提交: 41 解决: 9
[提交] [状态] [讨论版] [命题人:admin]
题目描述
一列火车n节车厢,依次编号为1,2,3,…,n。每节车厢有两种运动方式,进栈与出栈,问n节车厢出栈的可能排列方式有多少种。
输入
一个数,n(n<=60000)
输出
一个数s表示n节车厢出栈的可能排列方式
样例输入
3
样例输出
5
典型的卡特兰数例子,但是阶乘要用质因数分解(算术基本定理)来算,不然会T
将上下阶乘质因数分解,然后约掉相同的质因数之后再乘,最后再除 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小的话,还可以用卡特兰数的递推公式
#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;
}