用到了卡特兰数的性质,还有高精度压位,筛法找素数

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

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

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

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

数据范围
1≤n≤60000
输入样例:
3
输出样例:
5

这道题的本质是卡特兰数

卡特兰数介绍(引用math73)

筛法求素数

最重要的是如何求解组合数,压位思想,还有组合数C(2n)(n)这个式子展开以后,用上下同时除以连续的质数的方法,将答案一点一点凑出来,而不是每次都是很长的数去除以一个数,这样降低了运行的时间。

	#include<iostream>
	#include<algorithm>
	#include<vector>
	using namespace std;
	const int N=120010;
	int powers[N];//每个质数的次数
	int primes[N],cnt;/质数表2~2*n内的质数
	bool st[N];//用来储存这个数是不是质数
	typedef long long ll;
	void get_primes(int n)//筛法判断是不是质数
	{
	    for(int i=2;i<=n;i++)
	    if(!st[i])
	    {
	        primes[cnt++]=i;
	        for(int j=i*2;j<=n;j+=i)
	        st[j]=true;
	    }
	}
	int get(int n,int p)//n的阶乘里有多少个因子p
	{
	    ll s=0;
	    while(n)
	    {
	        s+=n/p;
	        n/=p;
	    }
	    return s;
	}
	void multi(vector<ll>&a,int b)//压位高精度运算
	{
	    int t=0;
	    for(int i=0;i<a.size();i++)
	    {
	        a[i]=a[i]*b+t;
	        t=a[i]/100000000;
	        a[i]%=100000000;
	    }
	    while(t)
	    {
	        a.push_back(t%100000000);
	        t/=100000000;
	    }
	}
	void out(vector<ll >&a)//输出
	{
	    printf("%lld",a.back());
	    for(int i=a.size()-2;i>=0;i--)
	    printf("%08lld",a[i]);
	    cout<<endl;
	}
	
	int main()
	{
	    int n;
	    cin>>n;
	    get_primes(n*2);
	    for(int i=0;i<cnt;i++)//分别求一下质数的次数
	    {
	        int p=primes[i];
	        powers[p]=get(n*2,p)-get(n,p)*2;//(C2n n)是2n的阶乘除以(n的阶乘*n的阶乘),所以乘2
	    }
	    int k=n+1;//分解质因数
	    for(int i=0;i<cnt&&primes[i]<=k;i++)
	    {
	        int p=primes[i],s=0;
	        while(k%p==0)
	        {
	            s++;
	            k/=p;
	        }
	        powers[p]-=s;
	    }
	    vector<ll>res;
	    res.push_back(1);
	        for(int i=2;i<=n*2;i++)
	           for(int j=0;j<powers[i];j++)
	            multi(res,i);
	           out(res);
	          return 0;
	        
	    }
	
	
	
	
	这个代码又是yxc大佬的源代码基础上写的注释,我还是太菜了。QAQ
posted @ 2020-02-03 12:41  arbor_one  阅读(300)  评论(0)    收藏  举报