この問題は動的計画法 (DP) を用いて解くことが出来ます。
部分列の条件に従い、以下のように状態遷移を考えることが出来ます。
状態を以下のように定義します:
dp[i][j]: i番目までの文字で、部分列が状態jとなるものの個数
部分列の状態jを以下のように定義します:
(
までできた(^
までできた(^^
までできた(^^)
完成次に、状態遷移を考えます:
(
の場合、状態0から状態1へ遷移する^
の場合、状態1から状態2へ、そして状態2から状態3へ遷移する)
の場合、状態3から状態4へ遷移する状態jの数を更新する際、前の状態の数を継承することも忘れてはいけません。これにより、状態0から状態3までの数は次の文字に対しても適用されます。
xxxxxxxxxx
using namespace std;
using namespace atcoder;
using mint = modint998244353;
int main() {
int n;
cin >> n;
string s;
cin >> s;
vector<vector<mint>> dp(n+1, vector<mint>(5));
dp[0][0] = 1;
for(int i = 0;i < n; ++i){
if(s[i] == '('){
dp[i+1][1] += dp[i][0];
}else if(s[i] == '^'){
dp[i+1][2] += dp[i][1];
dp[i+1][3] += dp[i][2];
}else{ // )
dp[i+1][4] += dp[i][3];
}
//状態の継承
for(int j = 0;j < 5; ++j){
dp[i+1][j] += dp[i][j];
}
}
cout << dp[n][4].val() << endl;
return 0;
}