消失的序列

题意

1 ∼ n 1 \sim n 1n,第 p o s pos pos 位为 x x x 的排列的个数,该排列需满足能通过栈将其排序成升序,对 1 0 9 + 7 10^9+7 109+7 取模。

数据范围

1 ≤ n ≤ 1 0 6 , 1 ≤ p o s , x ≤ n 1 \leq n \leq 10^6,1 \leq pos,x \leq n 1n106,1pos,xn

题解

看到题目应该先考虑满足这种条件的排列实质上是什么?

可以发现:如果一个排列能够通过栈排成升序,那么将升序的 1 ∼ n 1 \sim n 1n 反过来操作,也能得到这个原排列,所以该排列和该操作顺序是一一对应的。

结论即:将 1 ∼ n 1 \sim n 1n 通过栈能得到的所有出栈顺序的数量就是 满足能通过栈排成升序的排列数。

也就是卡特兰数。发现了这一点之后,接下来就是经典套路了——考虑卡特兰数的组合意义和几何意义

我们将入栈看作左括号 ( ( (,出栈看作右括号 ) ) )。于是如果不考虑第 p o s pos pos 位的限制,答案 C a t n Cat_n Catn 就是长度为 2 n 2n 2n 的合法括号个数,即 C 2 n n − C 2 n n − 1 C_{2n}^{n}-C_{2n}^{n-1} C2nnC2nn1

接着考虑第 p o s pos pos 位的影响,第 p o s pos pos 位为 x x x 实质上就是第 p o s pos pos 个左括号要和第 x x x 个右括号配对,那么我们就枚举第 p o s pos pos 个左括号在 2 n 2n 2n 个位置中的位置 i i i,于是 i i i 前面就有 i − p o s i-pos ipos 个右括号, p o s − 1 pos-1 pos1 个左括号,求满足这些条件的方案数,剩下的读者们可以自己去算算组合数。

代码

#include<bits/stdc++.h>
#define LL long long
using namespace std;
const int P=1e9+7;
const int N=2e6+10;
inline int ksm(int a,int b){
	int s=1;while(b){
		if(b&1)s=1ll*s*a%P;
		a=1ll*a*a%P;b>>=1;
	}
	return s;
}
int n,pos,x;
int jc[N],f[N],inv[N];
inline int qmod(int X){return (X>=P)?X-P:((X<0)?X+P:X);}
inline int C(int n,int m){
	if(n<m)return 0;
	return 1ll*jc[n]*inv[m]%P*inv[n-m]%P;
}
inline int cat(int n){return qmod(C(2*n,n)-C(2*n,n-1));}
inline int S(int n,int m){
	if(n<0||m<0)return 0;
	return qmod(C(n+m,m)-C(n+m,n+1));
}
int main(){
	LL ans=0;
	scanf("%d%d%d",&n,&pos,&x);
	jc[0]=1;for(int i=1;i<=2*n;++i)jc[i]=1ll*jc[i-1]*i%P;
	inv[0]=1;inv[n<<1]=ksm(jc[n<<1],P-2);
	for(int i=2*n-1;i;--i)inv[i]=1ll*inv[i+1]*(i+1)%P;
	for(int i=pos;i<=pos*2-1;++i){
		int s1=S(pos-1,i-pos);
		int s2=S(x-i+pos-1,x-i+pos-1);
		int s3=S(n-x,n-pos-x+i-pos+1);
		//cout<<"FAQ "<<s1<<" "<<s2<<" "<<s3<<" "<<i<<endl;
		ans=qmod(ans+1ll*s1*s2%P*s3%P);
	}
	printf("%lld\n",ans);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值