A - No Majority(DP 动态规划)[AtCoder Grand Contest 060]

题目如下:

在这里插入图片描述

思路 or 题解:

对于一个子串, 如果长度为 l e n len len, 如果该子串中任意一个字符的出现个数 大于 l e n 2 \frac{len}{2} 2len 那该字符串为 U n g o o d Ungood Ungood
反之,如果任意子串, 长度设为 l e n len len, 如果该子串中任意一个字符的出现个数 小于等于 l e n 2 \frac{len}{2} 2len, 那该字符串为 G o o d Good Good

核心:
如果一个子串有字符超过一半,那肯定可以找到一个长度 ≤ 3 \le3 3 的子串满足字符超过一半。

我们可以用 DP(动态规划) 的思想去写
d p [ i ] [ j ] [ k ] dp[i][j][k] dp[i][j][k], i i i位置, i i i位置字符为 j j j i − 1 i-1 i1位置字符为 k k k 的合法方案数。

转移:
判断合法,如果合法:
d p [ i ] [ j ] [ k ] = ( d p [ i ] [ j ] [ k ] + d p [ i − 1 ] [ k ] [ z ] ) dp[i][j][k] = (dp[i][j][k] + dp[i - 1][k][z]) dp[i][j][k]=(dp[i][j][k]+dp[i1][k][z])

时间复杂度: O ( n × 2 6 3 ) O(n \times 26^3) O(n×263)

AC 代码如下:

const int mod = 998244353;
const int inf = 2147483647;
const int N = 5009;
int n;
char s[N];
int dp[N][27][27];
bool check(int a, char aa, int b, char bb)
{
    if ((aa != '?' && aa - 'a' != a) || (bb != '?' && bb - 'a' != b))
        return false;
    return true;
}
bool check2(int a, int b, int c)
{
    if (a == b || a == c || b == c)
        return false;
    return true;
}
void solve()
{
    cin >> n;
    cin >> s + 1;
    for (int i = 0; i < 26; i++)
        for (int j = 0; j < 26; j++)
            if (i != j && check(i, s[2], j, s[1]))
                dp[2][i][j] = 1;
        
    for (int i = 3; i <= n; i++)
        for (int j = 0; j < 26; j++)
            for (int k = 0; k < 26; k++)
                for (int z = 0; z < 26; z++)
                {
                    if (!check(j, s[i], k, s[i - 1]) || !check2(j, k, z))
                        continue;
                    dp[i][j][k] = (dp[i][j][k] + dp[i - 1][k][z]) % mod;
                }

    int ans = 0;
    for (int i = 0; i < 26; i++)
        for (int j = 0; j < 26; j++)
            ans = (ans + dp[n][i][j]) % mod;
    cout << ans << '\n';
}
int main()
{
    buff;
    solve();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Joanh_Lan

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值