2022HBCPC 优美的字符串

优美的字符串

题目描述

我们称一个字符串是优美的,当且仅当这个字符串中不存在长度严格大于 2 的回文串。

现在有 m 种不同的字符,那么在可以组成的长度恰好为 nm^n 个不同的字符串中,请求出一共有多少个字符串是优美的,输出答案对 1000000007 取模后的结果即可。

题目分析

字符串中不能存在严格大于2的回文串,则每相邻的三个字符都不能是回文串。三个字符非回文的情况有三aab abb abc。围绕此三种情况进行思考即可。

可以向动态规划的思想上靠拢(当时也没怎么往这边想

定义集合f[i][3]:
f[i][0]:以i结尾,最后三个字符为 abc类的方案的集合
f[i][1]:以i结尾,最后三个字符为 aab类的方案的集合
f[i][2]:以i结尾,最后三个字符为 abb类的方案的集合

根据三种状态的特点我们可以得到状态转移方程

f[i][0] = f[i - 1][1] * (m - 2) + f[i - 1][0] * (m - 2)
f[i][1] = f[i - 2][0] * (m - 2) 
f[i][2] = f[i - 1][0] + f[i - 1][1];

值得注意的是,当n<3时的情况需要特判

  • n == 1时,方案数为m
  • n == 2时,方案数为 m + m * (m - 1) 即m * m
    • 类似aa bb 也为合法方案,即为第一个 m
    • 从m个数中任意选择两个,即为 m*(m-1)

值得注意的是取模一定要细心

code
#include<bits/stdc++.h>

using namespace std;

const int N = 1e6 + 10, mod = 1000000007;
typedef long long ll;

ll n, m, k, t;
ll f[N][3];

int main()
{
    cin >> n >> m;

    if(n < 3)
    {
        if(n == 1) cout << m << "\n";
        else
        {
            ll ans = m * m % mod;
            cout << ans % mod << "\n";
        }
        return 0;
    }
   
    f[3][0] = m * (m - 1) % mod * (m - 2) % mod;
    f[3][1] = f[3][2] = m * (m - 1) % mod;

    for(int i = 4; i <= n; i ++)
    {
        f[i][0] = (f[i - 1][1] * (m - 2)) % mod + (f[i - 1][0] * (m - 2) % mod);
        f[i][1] = f[i - 1][2] * (m - 2) % mod;
        f[i][2] = (f[i - 1][0] % mod) + (f[i - 1][1] % mod) % mod;
    }

    cout << (f[n][0] + f[n][1] + f[n][2]) % mod << "\n";

    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值