火车进出栈【卡特兰数】【高精度】【压位】【压int位】

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

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

进出栈符合+±-,前缀‘-’的个数比‘+’少 的排列方式:卡特兰数 C(n,2n)/(n+1)
证明:C(n,2
n)- 不可能的状态;
不可能的状态=(明安图中非降路径)=C(n-1,2n);
**化解得:C(n,2
n)/(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;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值