比赛名称: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;
}


















