P7914 [CSP-S 2021] 括号序列
题目

分析
考场上同样傻逼了,居然没调出来,赛后发现两个数组是可行的,考场代码改改加个后缀和就过了。/tuu
题目直接线性dp发现并不好转移,然后 \(n=500\) 一脸 \(n^3\) ,于是可以考虑区间 \(dp\) 。
然后常规设状态 \(dp[l,r]\) 表示 \([l,r]\) 满足题意的方案数。
然后照着题意模拟 \(dp\) 即可。
接下来会发现其实 \(AB,ASB\) 会算重。
比如:
6 1
()()()
显然应该输出 1。
然后我们考虑单独拿出来这部分的转移,\(AB,ASB\) 的情况只在第一个断点转移,这样就合法了。
于是记一个 \(dp1\) 表示可以用后两者转移的答案,修改 \(dp\) 的含义为:不可以用后两者转移的答案。
接下来发现转移其实是 \(O(n^4)\) 的,因为 \(ASB\) 需要枚举两个断点。
但是这个显然是可以后缀和优化的,于是复杂度 \(O(n^3)\) ,具体见代码。
代码
#include<bits/stdc++.h>
using namespace std;
template<typename T>
void read(T &x){
x=0;bool f=false;char ch=getchar();
while(!isdigit(ch)){f|=ch=='-';ch=getchar();}
while(isdigit(ch)){x=x*10+(ch^48);ch=getchar();}
x=f?-x:x;
return ;
}
const int N=505,M=2e5+5,INF=1e9+7,MOD=1e9+7;
int n,K,dp[N][N],pre[N],dp1[N][N],R[N],sum[N][N];
char str[N];
bool Checkleft(char x){
if(x=='(') return true;
if(x=='?') return true;
return false;
}
bool Checkright(char x){
if(x==')') return true;
if(x=='?') return true;
return false;
}
bool Checks(int l,int r){
if(r-l+1>K) return false;
int res=pre[r]-pre[l-1];
if(res==r-l+1) return true;
return false;
}
bool Checkss(char x){return (x=='*'||x=='?');}
inline void incc(int &x,int y){x+=y;if(x>=MOD)x-=MOD;return ;}
inline int dec(int x,int y){x-=y;if(x<0) x+=MOD;return x;}
inline int inc(int x,int y){x+=y;if(x>=MOD)x-=MOD;return x;}
signed main(){
// freopen("bracket.in","r",stdin);
// freopen("bracket.out","w",stdout);
read(n),read(K);
scanf("%s",str+1);
for(int i=1;i<=n;i++) pre[i]=pre[i-1]+(str[i]=='*'||str[i]=='?');
for(int i=n;i>=1;i--){
if(Checkss(str[i])&&Checkss(str[i+1])) R[i]=R[i+1];
else if(Checkss(str[i])) R[i]=i;
else R[i]=0;
R[i]=min(R[i],i+K-1);
}
for(int len=2;len<=n;len++){
for(int l=1;l+len-1<=n;l++){
int r=l+len-1;
if(len>=4){if(Checkleft(str[l])&&Checkright(str[r])) incc(dp[l][r],dp1[l+1][r-1]);}//(A)
if(len>=5){
for(int k=l+1;k<=r-3;k++){//(SA)
if(Checkleft(str[l])&&Checkright(str[r])&&Checks(l+1,k)) incc(dp[l][r],dp1[k+1][r-1]);
}
for(int k=r-1;k>=l+3;k--){//(AS)
if(Checkleft(str[l])&&Checkright(str[r])&&Checks(k,r-1)) incc(dp[l][r],dp1[l+1][k-1]);
}
}
if(len>=4){//AB
for(int k=l+1;k<=r-2;k++) incc(dp1[l][r],1ll*dp[l][k]*dp1[k+1][r]%MOD);
}
if(len>=5){//ASB
for(int k1=l;k1<=r-3;k1++){
int rval=min(R[k1+1]+2,r);
if(!R[k1+1]) continue;
incc(dp1[l][r],1ll*dp[l][k1]*dec(sum[min(k1+2,r)][r],sum[rval][r])%MOD);
// for(int k2=k1+2;k2<=r-1;k2++){
// if(Checks(k1+1,k2-1)) incc(dp1[l][r],1ll*(dp[l][k1])*(dp1[k2][r])%MOD);
// }
}
}
if(len==2){//()
if(Checkleft(str[l])&&Checkright(str[r])) incc(dp[l][r],1);
}
if(len>=3){//(S)
if(Checkleft(str[l])&&Checkright(str[r])&&Checks(l+1,r-1)) incc(dp[l][r],1);
}
incc(dp1[l][r],dp[l][r]);
}
for(int i=1;i<=n;i++) sum[i][i]=0;
for(int len=2;len<=n;len++){
for(int l=1;l+len-1<=n;l++){
int r=l+len-1;
sum[l][r]=inc(sum[l+1][r],dp1[l][r]);
}
}
}
printf("%d",dp1[1][n]);
return 0;
}

浙公网安备 33010602011771号