题目描述1

代码

c
java
python
#include <iostream>
#include <vector>

using namespace std;

class Solution {
public:
    int possibleStringCount(string word, int k) {
        int n = word.size(), mod = 1e9+7;
        vector<int> x;
        //  分组:
        //  假定输入字符串 word = "aaabb", k = 3
        //  首先,把它拆成连续相同字符的块:word = "aaa" | "bb",
        //  所以块长度数组 x = [3, 2],总块数 m = 2
        for (int i=0, cnt=1; i<n; i++) {
            if (i+1<n && word[i]==word[i+1]) cnt++;
            else { x.push_back(cnt); cnt=1; }
        }
        //  每个相同字符块内,你可以截取任意长度 l (1 ≤ l ≤ xᵢ)作为最终保留。
        //  块与块之间互不影响,总方案数就是各块方案数的乘积:
        //  块 1(长度 3):可选长 1、2、3 → 3 种
        //  块 2(长度 2):可选长 1、2 → 2 种
        //  于是 total = 3 × 2 = 6(ab, aab, aaab, abb, aabb, aaabb).
        long long total = 1;
        for (int len : x)
            total = total * len % mod;
        // 当字符串块数 m 大于等于 k 时,直接返回 total.
        // 当字符串块数 m 小于 k 时,说明有些方案会导致字符块长度不足 k,需要剪除它们.
        int m = x.size();
        if (m >= k) return total;           
        // 使用动态规划与前缀和的方法剪除字符块长度不足 k 的情况,没看懂
        // dp[i][j] 表示 前 i 个原始块,恰好截取后构成 j 个块的方案数.
        // 令 dp[0][0] = 1(还没处理任何块时,截成 0 块只有一种“空”方案).
        vector<vector<int>> dp(m+1, vector<int>(k));
        dp[0][0] = 1;
        for (int i=0; i<m; i++) {
            vector<int> S(k+1);
            for (int j=0; j<k; j++)
                S[j+1] = (S[j] + dp[i][j]) % mod;
            for (int j=0; j<k; j++) {
                int left = max(0, j - x[i]);
                dp[i+1][j] = (S[j] - S[left] + mod) % mod;
            }
        }
        long long bad = 0;
        for (int j=0; j<k; j++)
            bad = (bad + dp[m][j]) % mod;

        return (total - bad + mod) % mod;
    }
};

int main() {
    Solution solution;
    int result = solution.possibleStringCount("aaabb", 3);
    std::cout << result << std::endl;
}

链接