解题思路
本题要求计算长度不超过 且包含子序列 "us" 的小写字母字符串数量。可以使用动态规划解决:
-
状态定义:
- 表示长度为 时的状态
- : 还未出现
- : 已经出现 ,还未出现
- : 已经出现
-
状态转移:
- // 前一个状态未出现 ,新字母不是
- // 新字母是 或 新字母不是
- // 新字母是 或 新字母任意
-
初始状态:
- // 除了 的所有字母
- // 只有
- // 不可能出现
-
最终结果:所有长度的 之和
代码
#include <iostream>
#include <vector>
using namespace std;
const int MOD = 1000000007;
int solve(int n) {
// dp[i][j] 表示长度为i时的状态j
vector<vector<long long>> dp(n + 1, vector<long long>(3, 0));
// 初始化长度为1的情况
dp[1][0] = 25; // 除了u的所有字母
dp[1][1] = 1; // 只有u
dp[1][2] = 0; // 不可能出现us
// 对每个长度进行转移
for (int i = 2; i <= n; i++) {
// 1. 还未出现u
dp[i][0] = (dp[i-1][0] * 25) % MOD;
// 2. 已出现u,未出现s
dp[i][1] = (dp[i-1][0] + dp[i-1][1] * 25) % MOD;
// 3. 已出现us
dp[i][2] = (dp[i-1][1] + dp[i-1][2] * 26) % MOD;
}
// 返回所有长度的us状态之和
long long result = 0;
for (int i = 2; i <= n; i++) {
result = (result + dp[i][2]) % MOD;
}
return result;
}
int main() {
int n;
cin >> n;
cout << solve(n) << endl;
return 0;
}
import java.util.Scanner;
public class Main {
static final int MOD = 1_000_000_007;
static int solve(int n) {
// dp[i][j] 表示长度为i时的状态j
long[][] dp = new long[n + 1][3];
// 初始化长度为1的情况
dp[1][0] = 25; // 除了u的所有字母
dp[1][1] = 1; // 只有u
dp[1][2] = 0; // 不可能出现us
// 对每个长度进行转移
for (int i = 2; i <= n; i++) {
// 1. 还未出现u
dp[i][0] = (dp[i-1][0] * 25) % MOD;
// 2. 已出现u,未出现s
dp[i][1] = (dp[i-1][0] + dp[i-1][1] * 25) % MOD;
// 3. 已出现us
dp[i][2] = (dp[i-1][1] + dp[i-1][2] * 26) % MOD;
}
// 返回所有长度的us状态之和
long result = 0;
for (int i = 2; i <= n; i++) {
result = (result + dp[i][2]) % MOD;
}
return (int)result;
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
System.out.println(solve(n));
sc.close();
}
}
def solve(n):
MOD = 10**9 + 7
# dp[i][j] 表示长度为i时:
# j=0: 还未出现u
# j=1: 已经出现u,还未出现s
# j=2: 已经出现us
dp = [[0] * 3 for _ in range(n + 1)]
# 初始化长度为1的情况
dp[1][0] = 25 # 除了u的所有字母
dp[1][1] = 1 # 只有u
dp[1][2] = 0 # 不可能出现us
# 对每个长度进行转移
for i in range(2, n + 1):
# 1. 还未出现u:前一个状态是未出现u,新字母不是u
dp[i][0] = (dp[i-1][0] * 25) % MOD
# 2. 已出现u,未出现s:
# - 前一个状态未出现u,这个位置是u
# - 前一个状态已出现u但未出现s,新字母不是s
dp[i][1] = (dp[i-1][0] + dp[i-1][1] * 25) % MOD
# 3. 已出现us:
# - 前一个状态已出现u未出现s,这个位置是s
# - 前一个状态已出现us,新加任何字母都行
dp[i][2] = (dp[i-1][1] + dp[i-1][2] * 26) % MOD
# 返回所有长度的us状态之和
result = 0
for i in range(2, n + 1):
result = (result + dp[i][2]) % MOD
return result
# 读取输入
n = int(input())
# 输出结果
print(solve(n))
算法及复杂度
- 算法:动态规划
- 时间复杂度: - 只需要遍历一次长度范围
- 空间复杂度: - 需要一个 的 数组