一列火车n节车厢,依次编号为1,2,3,…,n。
每节车厢有两种运动方式,进栈与出栈,问n节车厢出栈的可能排列方式有多少种。
进出栈符合+±-,前缀‘-’的个数比‘+’少 的排列方式:卡特兰数 C(n,2n)/(n+1)
证明:C(n,2n)- 不可能的状态;
不可能的状态=(明安图中非降路径)=C(n-1,2n);
**化解得:C(n,2n)/(n+1)**
一:卡特兰数的本质 ±序列。
二:±序列的本质 明安图。
三:我国清朝明安图(蒙古人)比外国人卡特兰更早发现使用明安图,卡特兰单纯命名了一下,就被载入史册。。。。。。
vector+高精度 求卡特兰数(比较慢)
//高精度乘法,
void mulit(vector<int> &res,int b){
int t=0;
for(int i=0;i<res.size();i++){
res[i]=res[i]*b+t;
t=res[i]/10;
res[i]%=10;
}
//处理进位,多余的数
while(t){
res.push_back(t%10);
t/=10;
}
}
// 高精度除法,
void div(vector<int> &res,int b){
int t=0;
for(int i=res.size()-1;i>=0;i--){
res[i]+=t*10;
t=res[i]%b;
res[i]/=b;
}
//低位到高位存,处理前导0;
while(res.size()>1&&res.back()==0) res.pop_back();
}
//求卡特兰数:{
vector<int>a;
a.push_back(1);
for(int i=2*n,j=1;j<=n;j++,i--){
mulit(a,i);
div(a,j);
}
div(a,n+1);
}
vector+高精度+压位 求卡特兰数(较快)
高精度压位提高速度
可以使用压位,将多个数压入一个向量来减少运算的次数。
特别需要注意的是,使用了压位技巧后,输出时一定要规范化向量各个元素的位数,比如压9位,除了向量末尾元素不需要进行位数限制外,其他元素一律在输出时使用%09lld进行格式控制,不足9位的前面补0,否则会导致输出的数结果不正确。
vector里int不存一位,存四位
特殊的输出:
一句话概括:除最高位外,一切不足P位的数字输出时需要在前面补上0使得满足P位
比如压2位 2 + 99 为例 最后会用到两个数组空间(一个放1,一个放1…)但是这两个一代表的意义不同,
第二个可以原样输出因为这是最高位(即整个数的长度modP后得到的剩余部分 这一部分是独立于其他部分的 如果补上0 最后就是0101 是不对的),第一个就需要补上一个0来使得输出101而不是11
压int位:
printf("%d",a[a.size()-1]);
for(int i=a.size()-2;i>=0;i--){
printf("%04d",a[i]);
}
压long long位:同理
void mulit(vector<int> &res,int b){
int t=0;
for(int i=0;i<res.size();i++){
res[i]=res[i]*b+t;
t=res[i]/10000;
res[i]%=10000;
}
while(t){
res.push_back(t%10000);
t/=10000;
}
}
void div(vector<int> &res,int b){
int t=0;
for(int i=res.size()-1;i>=0;i--){
res[i]+=t*10000;
t=res[i]%b;
res[i]/=b;
}
while(res.size()>1&&res.back()==0) res.pop_back();
}
//压位后特殊的输出
printf("%d",a[a.size()-1]);
for(int i=a.size()-2;i>=0;i--){
printf("%04d",a[i]);
}
质因数分解+vector+高精度+压位 求卡特兰数(标准)
分子 父母 分解为质数相乘,分母指数减分子指数;
//2n的阶乘除以n的阶乘*n的阶乘
//prime表,cnt ,book st晒;
//找到俩坨数的数数指数,接去;
//
#include<iostream>
#include<vector>
using namespace std;
const int N=2*60000+10;
int prime[N],cnt;
int power[N];
bool st[N];
void get_prime(int n){
for(int i=2;i<=n;i++){
if(!st[i]){
prime[cnt++]=i;
for(int j=i+i;j<=n;j+=i){
st[j]=true;
}
}
}
}
//n的阶乘有几个p
int get(int n,int p){
int s=0;
while(n){
s+=n/p;
n/=p;
}
return s;
}
void multi(vector<int>&a,int b){
int t=0;
for(int i=0;i<a.size();i++){
a[i]=a[i]*b+t;
t=a[i]/10000;
a[i]%=10000;
}
while(t){
a.push_back(t%10000);;
t/=10000;
}
}
int main(){
int n;
cin>>n;
//prime
get_prime(2*n);
for(int i=0;i< cnt;i++){
int p=prime[i];
power[p]=get(2*n,p)-2*get(n,p);
}
//n+1分解为质数
int k=n+1;
for(int i=0;i<cnt&&prime[i]<=k;i++){
int p=prime[i],s=0;
while(k%p==0){
s++;
k/=p;
}
power[p]-=s;
}
vector<int > res;
res.push_back(1);
for(int i=2;i<=n* 2;i++){
for(int j=0;j<power[i];j++){
multi(res,i);
}
}
cout<<res.back();
for(int i=res.size()-2;i>=0;i--) printf("%04d",res[i]);
cout<<endl;
return 0;
}