CCPC 河北省赛 优美的字符串 - DP

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

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

Input

输入仅一行两个整数,分别表示 n 和 m(1≤n≤1e6,1≤m≤1e9)。

Output

输出仅一行一个整数,表示答案对 1000000007 取模后的结果。

Sample Input 1

3 3

Sample Output 1

18

代码长度限制

16 KB

时间限制

1000 ms

内存限制

256 MB

 分析:

        分析字符串特点发现2以内的没有限制,最小出现分类的从长度为3的字符串开始,以长度为3的字符串结尾分类讨论,具有以下几种形式:

1.abc  三个字母都不相同

2.aab  前两个字母相同最后一个不i同

3.abb  后两个字母相同第一个不同

其他情况都不符合题意,因此可以开二维数组f[i][0/1/2]三种来分别表示以上三种情况长度为n的字符串方案数量。

第一种:

        以abc形式结尾的长度为i的字符串的方案数,那么就要保证i之前的两个字符必须不相同,最后两位不相同的有abc和aab两种,最后一个字符也就是当前i所在位置的字符与前两个字符也不能一样,所以i处可以放入的字符有(m-2)种,因此递推方程就是:

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

第二种:

        以aab结尾的长度为i的方案数,保证前两位相同,最后两位相同的有abb一种,xaab字符串因为要满足不是回文字符串,因此i处的字符也只有m-2种,递推方程:

f[i][1] = f[i-1][2] * (m-2).

第三种:

        以abb结尾的长度为i的方案数,和上面一样,最后两位不同的有abc和aab两种,因为i处的字符要与前一个相同,因此i处的字符就只有1种。递推方程就是:

f[i][2] = f[i-1][0] + f[i-1][1].

数据范围过大要在计算过程中边算边取模,防止爆long long 。

代码:

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

const int N=1e6+10;
const int mod=1000000007;

ll f[N][4];

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

    int n;
    ll m;
    cin>>n>>m;
    f[3][0]=m*(m-1)%mod*(m-2)%mod;
    f[3][1]=m*(m-1)%mod;
    f[3][2]=m*(m-1)%mod;
    for(int i=4;i<=n;i++)
    {
        f[i][0]=(f[i-1][0]*(m-2)%mod+f[i-1][1]*(m-2)%mod)%mod;
        f[i][1]=f[i-1][2]*(m-2)%mod;
        f[i][2]=(f[i-1][0]+f[i-1][1])%mod;
    }
    ll ans=0;
    for(int i=0;i<3;i++) ans+=f[n][i];
    if(n==1) cout<<m<<'\n';
    else if(n==2) cout<<m*m<<'\n';
    else cout<<ans%mod<<'\n';
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值