题意:给定
1
N
1~N
1 N这
N
N
N个整数和一个无限大的栈,每个数都要进栈并出栈一次。如果进栈的顺序为
1
,
2
,
⋯
 
,
N
1,2,\cdots,N
1,2,⋯,N,那么可能的出栈序列有多少种?
题解:先考虑搜索
c
o
d
e
:
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的幂次,不是一位一位算的,公式是
n
2
+
n
2
2
+
n
2
3
+
⋯
\frac{n}{2}+\frac{n}{2^2}+\frac{n}{2^3}+\cdots
2n+22n+23n+⋯,然后就能做出整个题目了。
c
o
d
e
:
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;
}