比赛名称:AtCoder Grand Contest 060
比赛链接:AtCoder Grand Contest 060
A - No Majority
题意:
一个由小写英文字母组成的字符串x被认为是好的,当且仅当以下条件得到满足。
x的每一个长度为2或更大的(连续的)子串都满足以下条件。
没有任何字符占据了该子串的大部分。
例如,acbca就不好,因为c占据了子串cbc的大部分。
给你一个长度为N的字符串S,由小写英文字母和? 你想用你选择的小写英文字母替换每个"?"来使S成为一个好的字符串。找出使S成为一个好字符串的方法的数量,模数为998244353。
思路:
假设一个字符串长度大于3,并且有一个字符占了大部分,我们都可以把它切分为长度为2和一个更大的子串(且有一个字符占了大部分),显然不能完全满足条件,所以只需要看长度小于等于3的子串,例如我们不能出现 aaa, aba, aab这种情况,即不能出现两个距离为1或2的字符。
很容易想到用DP解决,构造状态,状态表示为前位的字符已经确定,第位的字符是,第位的字符是时的替换方案数。
AcCode:
#include <bits/stdc++.h>
#define int long long
#define mod 998244353
using namespace std;
const int N = 5050;
int f[N][30][30];
signed main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
cin >> n;
string s;
cin >> s;
s = ' ' + s;
f[0][26][27] = 1;
for (int i = 1; i <= n; i++){
for (int j = 0; j <= 27; j++){
for (int k = 0; k <= 27; k++){
if (!f[i - 1][j][k] || j == k) continue;
for (int l = 0; l < 26; l++){
if (j == l || l == k) continue;
if (s[i] != '?' && s[i] != l + 'a') continue;
(f[i][k][l] += f[i - 1][j][k]) %= mod;
}
}
}
}
int ans = 0;
for (int i = 0; i < 26; i++){
for (int j = 0; j < 26; j++){
(ans += f[n][i][j]) %= mod;
}
}
cout << ans << "\n";
return 0;
}