解题思路

本题要求计算长度不超过 且包含子序列 "us" 的小写字母字符串数量。可以使用动态规划解决:

  1. 状态定义:

    • 表示长度为 时的状态
    • : 还未出现
    • : 已经出现 ,还未出现
    • : 已经出现
  2. 状态转移:

    • // 前一个状态未出现 ,新字母不是
    • // 新字母是 或 新字母不是
    • // 新字母是 或 新字母任意
  3. 初始状态:

    • // 除了 的所有字母
    • // 只有
    • // 不可能出现
  4. 最终结果:所有长度的 之和

代码

#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))

算法及复杂度

  • 算法:动态规划
  • 时间复杂度: - 只需要遍历一次长度范围
  • 空间复杂度: - 需要一个 数组