题意:给定1 N1~N1 N这NNN个整数和一个无限大的栈,每个数都要进栈并出栈一次。如果进栈的顺序为1,2,⋯ ,N1,2,\cdots,N1,2,⋯,N,那么可能的出栈序列有多少种?
题解:先考虑搜索
code:code:code:
#include<bits/stdc++.h>
using namespace std;
int n;
vector<int>state1;
stack<int>state2;
int state3=1,cnt=20;
void dfs()
{
if(!cnt)return ;
if(state1.size()==n){
cnt--;
for(auto &p:state1)cout<<p;
cout<<endl;
return ;
}
if(state2.size()){
state1.push_back(state2.top());
state2.pop();
dfs();
state2.push(state1.back());
state1.pop_back();
}
if(state3<=n){
state2.push(state3);
state3++;
dfs();
state3--;
state2.pop();
}
}
int main()
{
cin>>n;
dfs();
return 0;
}
但是数据范围如果是百万级别的话,搜索肯定是不行的,可以将出队序列转化成一个′+−′'+-'′+−′序列,进栈为′+′'+'′+′,出栈为′−′'-'′−′,只要能够求出所有合理的′+−′'+-'′+−′序列,之后通过将序列转化为图上的路径,所有序列最后都会走到(n,n)(n,n)(n,n),不合理的序列通过适当转换都会走到(n−1,n+1)(n-1,n+1)(n−1,n+1),所以卡特兰数就是C(n,2∗n)−C(n−1,2∗n)C(n,2*n)-C(n-1,2*n)C(n,2∗n)−C(n−1,2∗n),适当化简为C(n,2∗n)N+1\frac{C(n,2*n)}{N+1}N+1C(n,2∗n),到这里就算结束了,但是这个组合数的算法是个大坑,只有使用质因数分解法算才不会导致被T,质因数分解法,比如看公式C(m,n)=n!m!(n−m)!C(m,n)=\frac{n!}{m!(n-m)!}C(m,n)=m!(n−m)!n!,可以将上下都质因数分解,然后最后将剩余的质因数想乘就是答案了,这样比那种边乘边除节省了很多时间,边乘边除高精度最后会升的很大,这种数字只会依次递增而已。一个阶乘的质因数分解也是有公式的,比如n!n!n!中2的幂次,不是一位一位算的,公式是n2+n22+n23+⋯\frac{n}{2}+\frac{n}{2^2}+\frac{n}{2^3}+\cdots2n+22n+23n+⋯,然后就能做出整个题目了。
code:code:code:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=120000+5;
int n,primes[N],cnt,st[N],powers[N];
void get_primes(int n)
{
for(int i=2;i<=n;i++){
if(!st[i]){
primes[cnt++]=i;
for(int j=i+i;j<=n;j+=i){
st[j]=1;
}
}
}
}
int get(int n,int p)
{
int s=0;
while(n){
s+=n/p;
n/=p;
}
return s;
}
void multi(vector<ll> &a,int b)
{
ll t=0;
for(int i=0;i<a.size();i++){
a[i]=a[i]*b+t;
t=a[i]/100000000;
a[i]=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]);
printf("\n");
}
int main()
{
int n;
scanf("%d",&n);
get_primes(n*2);
for(int i=0;i<cnt;i++){
int p=primes[i];
powers[p]=get(2*n,p)-get(n,p)*2;
}
int k=n+1;
for(int i=0;i<cnt&&primes[i]<=k;i++){
while(k%primes[i]==0){
k/=primes[i];
powers[primes[i]]--;
}
}
vector<ll>res;
res.push_back(1);
for(int i=0;i<cnt;i++){
for(int j=0;j<powers[primes[i]];j++){
multi(res,primes[i]);
}
}
out(res);
return 0;
}