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);
}
本文来自博客园,作者:liyixin,转载请注明原文链接:https://www.cnblogs.com/liyixin0514/p/18468517