比赛的时候想半天没有想出来,赛后补题发现是一道动态规划问题。
定义一个二维dp数组,第二维度维护当前字符串结尾的三种可能,第一种以s结尾,第二种最后以sh为结尾,第三种则是以其他字符结尾。设定最多组成3个shs,不然会发生重复。
if(j==9)代表刚好组成3个shs,下一个状态可以为当前字符串加上26个字符中随便一个,即加上26ll*dp[i][j]。
if(j%3==1) 表示以s结尾,以s结尾的情况下加上s还是j不变,i+1;以s结尾的情况下加上h变为第二种情况即以sh结尾,j+1,i+1;以s结尾的情况下加上其他字符变为第三种情况,即以其他字符结尾,j/3*3,i+1。
else 表示以sh或者以其他字符结尾的情况,此时shs的数量未达到3个。若是以sh结尾,则加上s后j+1刚好跳到下一个状态,或者加上一个其他字符,j变为j*3/3;若是以其他字符结尾,则加上s后跳转到j+1,或者加上一个其他字符,j变成j*3/3;因此这两种情况都是一样的,可以放在一起讨论。
最后输出dp[n][9](代表刚好组成三个shs的情况)
#include<bits/stdc++.h>
using namespace std;
const int mod=1e9+7;
int dp[1000010][10];//第二维度只包含s,sh,shs三种情况
int main(){
int n;
scanf("%d",&n);
dp[0][0]=1;//定义初始状态
for(int i=0;i<n;i++){
for(int j=0;j<10;j++){
if(j==9){//刚好组成3个shs
dp[i+1][j]=(dp[i+1][j]+26ll*dp[i][j])%mod;//下一个状态由当前状态乘26所得
}
else if(j%3==1){//以s结尾
dp[i+1][j]=(dp[i+1][j]+dp[i][j])%mod;//s后加的字符仍为s ,第二维度仍为j
dp[i+1][j+1]=(dp[i+1][j+1]+dp[i][j])%mod;//s后加的字符为h,变为第二种情况以sh结尾,第二维度变为j+1
dp[i+1][j/3*3]=(dp[i+1][j/3*3]+24ll*dp[i][j])%mod;//s后加的字符为除s和h外的任意24个字符,重新变为整shs的情况
}
else {//以sh和以其他字符结尾的一起讨论 此时j可能为0可能为2
dp[i+1][j+1]=(dp[i+1][j+1]+dp[i][j])%mod;//以sh为结尾的情况下可以选择以s为结尾,下一个状态就直接加上dp[i][j] 或者 以其他字符为结尾的情况下选择以s为结尾
dp[i+1][j/3*3]=(dp[i+1][j/3*3]+25ll*dp[i][j])%mod; //以sh为结尾的情况下加上了除s外的其他字符,重新变为整shs的情况 或者 以其他字符为结尾的情况下再选择以其他字符结尾
}
}
}
printf("%d\n",dp[n][9]);//最后输出的是刚好有3个shs的情况,所以第二维度为9
}