题目描述
小 w 在赛场上遇到了这样一个题:一个长度为 nn 且符合规范的括号序列,其有些位置已经确定了,有些位置尚未确定,求这样的括号序列一共有多少个。
身经百战的小 w 当然一眼就秒了这题,不仅如此,他还觉得一场正式比赛出这么简单的模板题也太小儿科了,于是他把这题进行了加强之后顺手扔给了小 c。
具体而言,小 w 定义“超级括号序列”是由字符 (
、)
、*
组成的字符串,并且对于某个给定的常数 kk,给出了“符合规范的超级括号序列”的定义如下:
()
、(S)
均是符合规范的超级括号序列,其中S
表示任意一个仅由不超过 \bm{k}k 个字符*
组成的非空字符串(以下两条规则中的S
均为此含义);- 如果字符串
A
和B
均为符合规范的超级括号序列,那么字符串AB
、ASB
均为符合规范的超级括号序列,其中AB
表示把字符串A
和字符串B
拼接在一起形成的字符串; - 如果字符串
A
为符合规范的超级括号序列,那么字符串(A)
、(SA)
、(AS)
均为符合规范的超级括号序列。 - 所有符合规范的超级括号序列均可通过上述 3 条规则得到。
例如,若 k = 3k=3,则字符串 ((**()*(*))*)(***)
是符合规范的超级括号序列,但字符串 *()
、(*()*)
、((**))*)
、(****(*))
均不是。特别地,空字符串也不被视为符合规范的超级括号序列。
现在给出一个长度为 nn 的超级括号序列,其中有一些位置的字符已经确定,另外一些位置的字符尚未确定(用 ?
表示)。小 w 希望能计算出:有多少种将所有尚未确定的字符一一确定的方法,使得得到的字符串是一个符合规范的超级括号序列?
可怜的小 c 并不会做这道题,于是只好请求你来帮忙。
输入格式
第一行,两个正整数 n, kn,k。
第二行,一个长度为 nn 且仅由 (
、)
、*
、?
构成的字符串 SS。
输出格式
输出一个非负整数表示答案对 {10}^9 + 7109+7 取模的结果。
输入输出样例
输入 #1复制
7 3 (*??*??
输出 #1复制
5
输入 #2复制
10 2 ???(*??(?)
输出 #2复制
19
【样例解释 #1】
如下几种方案是符合规范的:
(**)*()
(**(*))
(*(**))
(*)**()
(*)(**)
【数据范围】
测试点编号 | n \len≤ | 特殊性质 |
---|---|---|
1 \sim 31∼3 | 1515 | 无 |
4 \sim 84∼8 | 4040 | 无 |
9 \sim 139∼13 | 100100 | 无 |
14 \sim 1514∼15 | 500500 | SS 串中仅含有字符 ? |
16 \sim 2016∼20 | 500500 | 无 |
对于 100 \%100% 的数据,1 \le k \le n \le 5001≤k≤n≤500。
上代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define rop(i,a,b) for(int i=(a);i<(b);i++)
#define per(i,a,b) for(int i=(a);i>=(b);i--)
#define por(i,a,b) for(int i=(a);i>(b);i--)
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
ll n,k,S[502][502],A[502][502],_A[502][502],S_A[502][502];
char s[502];
bool isl(char c) {return c=='('||c=='?';}//判断该字符是否是/能填上(
bool isr(char c) {return c==')'||c=='?';}//判断该字符是否是/能填上)
bool isx(char c) {return c=='*'||c=='?';}//判断该字符是否是/能填上*
int main(){
scanf("%lld%lld%s",&n,&k,s+1);
rep(l,1,n){//预处理S[l][r]
if(!isx(s[l])) continue;//不是*则枚举下一个l
S[l][l]=1;
rep(r,l+1,min(n,l+k-1)){//最多连续k个*,同时不能越界
if(!isx(s[r])) break;//如果s[r]不是*,再往后就一定构不成连续的*
S[l][r]=1;
}
}
per(l,n-1,1){
rep(r,l+1,n){
if(r-l==1){//l与r连着,[l,r]只有作为()才能产生贡献
if(isl(s[l])&&isr(s[r])) A[l][r]=_A[l][r]=1;//判断[l,r]是否为()
continue;
}
if(isl(s[l])&&isr(s[r])){//判断外层()
A[l][r]+=S[l+1][r-1],A[l][r]%=mod;//(S)
A[l][r]+=A[l+1][r-1],A[l][r]%=mod;//(A)
rop(i,l+1,r-1) A[l][r]+=S[l+1][i]*A[i+1][r-1]%mod,A[l][r]%=mod;//(SA)
rop(i,l+1,r-1) A[l][r]+=A[l+1][i]*S[i+1][r-1]%mod,A[l][r]%=mod;//(AS)
}
_A[l][r]=A[l][r];//此时包含型情况的枚举完毕,_A[l][r]==此时的A[l][r]
rop(i,l,r) S_A[l][r]+=S[l][i]*_A[i+1][r]%mod,S_A[l][r]%=mod;//维护S_A
rop(i,l,r) A[l][r]+=A[l][i]*_A[i+1][r]%mod,A[l][r]%=mod;//A_A
rop(i,l,r) A[l][r]+=A[l][i]*S_A[i+1][r]%mod,A[l][r]%=mod;//AS_A
}
}
printf("%lld",A[1][n]);
return 0;
}