我们称一个字符串是优美的,当且仅当这个字符串中不存在长度严格大于 2 的回文串。
现在有 m 种不同的字符,那么在可以组成的长度恰好为 n 的 m^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
值得注意的是取模一定要细心
#include
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;
}