题解:P12264 『STA - R9』咏叹调调律
update:应 jijidawang 要求在末尾换成了一份调试版代码
可能是内测人员题解。
这个题场上很多选手都写了假的 dp,获得了
首先子串的可删性是不好刻画的,首先看一下特征,就是
那么我们发现
现在考虑简单情况,就是一个括号序列,可以填写
发现如果一个序列合法的话必然将一个前缀的问号全换成左括号,后缀全部换成右括号不劣,并且这样合法的分界点只有一个,设
接下来考虑原问题,这个
然后有一个深刻的问题就是
那么我们仿照上面的括号处理方式,先来考虑如何判定:
-
每当遇到一个单独的右括号的时候肯定优先匹配双左括号,注意剩下的这一个括号是特殊的(只能用
\text{A} 也就是单右括号删除,但是可以被\text{B} 抢夺)。 -
每当遇到一个双右括号的时候优先匹配双左括号,否则的话匹配两个单左括号。
于是设
直接 dp 就好了,代码非常难看。
提供一份调试用代码,输入
它实现和正解的 dp 几乎没区别,就是把答案集合全部记录了,一些实现细节也可以看里面的。
#include<bits/stdc++.h>
using namespace std;
using llt=long long;
const llt N=20,mod=998244353;
llt n;vector<string> dp[N][N][N][3][2],Ans;
void add(vector<string> &S,vector<string> A,char s){if(s=='O')for(auto v:A) S.push_back(v);else for(auto v:A) S.push_back(v+s);}
int main()
{
cin>>n;
dp[0][0][0][0][0].push_back("");
for(int i=1;i<=n;i++)
{
for(int j=0;j<=i;j++)
for(int k=0;k+j<=i;k++)
{
if(j>=1)
add(dp[i][j][k][0][0],dp[i-1][j-1][k][0][0],'A'),
add(dp[i][j][k][1][0],dp[i-1][j-1][k][1][0],'A'),
add(dp[i][j][k][2][0],dp[i-1][j-1][k][2][0],'A');
add(dp[i][j][k][(k>0)+1][1],dp[i-1][j+1][k][0][1],'A');
add(dp[i][j][k][(k>0)+1][1],dp[i-1][j+1][k][0][0],'A');
add(dp[i][j][k][0][1],dp[i-1][j][k][1][1],'A');
add(dp[i][j][k][0][1],dp[i-1][j][k][2][1],'A');
add(dp[i][j][k][0][0],dp[i-1][j+1][k][0][0],'B'),
add(dp[i][j][k][0][1],dp[i-1][j+1][k][0][1],'B'),
add(dp[i][j][k][1][0],dp[i-1][j+1][k][1][0],'B'),
add(dp[i][j][k][1][1],dp[i-1][j+1][k][1][1],'B'),
add(dp[i][j][k][2][0],dp[i-1][j+1][k][2][0],'B'),
add(dp[i][j][k][2][1],dp[i-1][j+1][k][2][1],'B');
if(k>=1)
add(dp[i][j][k][0][0],dp[i-1][j][k-1][0][0],'C'),
add(dp[i][j][k][0][1],dp[i-1][j][k-1][0][1],'C'),
add(dp[i][j][k][1][0],dp[i-1][j][k-1][1][0],'C'),
add(dp[i][j][k][1][1],dp[i-1][j][k-1][1][1],'C'),
add(dp[i][j][k][2][0],dp[i-1][j][k-1][2][0],'C'),
add(dp[i][j][k][2][1],dp[i-1][j][k-1][2][1],'C');
}
for(int k=0;k<=i;k++)
add(dp[i][0][k][0][0],dp[i-1][0][k+2][0][0],'B'),
add(dp[i][0][k][0][1],dp[i-1][0][k+2][0][1],'B'),
add(dp[i][0][k][1][0],dp[i-1][0][k+2][1][0],'B'),
add(dp[i][0][k][1][1],dp[i-1][0][k+2][1][1],'B'),
add(dp[i][0][k][0][1],dp[i-1][0][k+1][0][0],'A'),
add(dp[i][0][k][0][1],dp[i-1][0][k+1][0][1],'A'),
add(dp[i][0][k][0][1],dp[i-1][0][k+1][2][1],'B');
for(int j=0;j<=i;j++) add(dp[i][j][0][1][1],dp[i][j][0][2][1],'O');
}
add(Ans,dp[n][0][0][0][0],'O');add(Ans,dp[n][0][0][0][1],'O');sort(Ans.begin(),Ans.end());
for(auto v:Ans) cout<<v<<endl;
return 0;
}