Unhappy Hacking

Unhappy Hacking

DP 做法显然,这里讲卡特兰数做法。

显然字符串 \(S\) 的内容不重要,我们只关心它的长度 \(len\)

输入序列一定是形如一堆无效 B 和输入、有效删除的混合东西,然后输入第一个有效字符,之后每两个有效字符间以及最后有一些输入和有效删除。

如果我们枚举无效删除的个数,把无效删除当做有效字符,输入序列就形如两个有效字符间有一堆输入、有效删除这样。

其中把输入当做 (,有效删除当做 ),有效字符也当做 (,答案一定是一个合法括号序列。

设有 \(i\) 个有效删除,则有 \(j=2n-2i-len\) 个无效删除

( 看作向上走,) 看作向下走,答案即为求从 \(S(0,0)\) 走到 \(T(2n,2n-2i)\) 且始终 (\(>\)),即不超过直线 \(y=0\)

\(T\) 关于直线 \(y=-1\) 的对称点 \(T'(2n,2i-2n-2)\)。答案就是 \(\binom{2n}{i}-\binom{2n}{i-1}\)

然后因为有效删除对应的输入有两种情况,所以答案要再乘上 \(2^i\)

预处理阶乘和逆元,总时间复杂度为 \(O(n)\)

Code

#include<bits/stdc++.h>
#define sf scanf
#define pf printf
using namespace std;
typedef long long ll;
const int N=5005,mod=1e9+7;
int n;
char s[N];
int len,i,j;
ll jc[N<<1];
void init(int n){
	jc[0]=1;
	for(int i=1;i<=n;i++){
		jc[i]=jc[i-1]*i%mod;
	}
}
ll ksm(ll a,ll b){
	ll s=1;
	while(b){
		if(b&1) s=s*a%mod;
		a=a*a%mod;
		b>>=1;
	}
	return s;
}
ll C(ll n,ll m){
	if(n<0 )return 0;
	return jc[n]*ksm(jc[n-m]*jc[m]%mod,mod-2)%mod;
}
ll ans;
void add(ll &a,ll b){
	a=(a+b)%mod;
}
int main(){
	sf("%d%s",&n,s);
	init(n);
	len=strlen(s);
	for(j=0;j<=(n-len)/2;j++){
		i=n-2*j-len;
		add(ans,(C(n,j)-C(n,j-1)+mod)%mod*ksm(2,j)%mod);
	}
	pf("%lld\n",ans);
}
posted @ 2024-10-15 21:33  liyixin  阅读(6)  评论(0编辑  收藏  举报