子序列中的 k 种字母

   https://kamacoder.com/problempage.php?pid=1028

 

1.先统计字符串中每个字母出现的次数

2.计算每种字母能贡献的非空子序列数量

3.有dp[j]个子序列恰好包括j种字母,

4.动态规划初始化dp[0] = 1,空子序列只有一种

5.从 0 到 25 遍历所有字母,但只处理那些 v[i] != 0 的字母,不断加入字母更新dp

下来自己画图

  • 倒序是为了防止重复使用同一个字母的贡献(类似背包)
  • dp[j-1]:之前已经选了 j-1 种字母的方案数
  • v[i]:当前字母 'a'+i 可以被选的方式数(非空)
  • dp[j-1] * v[i]:把当前字母加入,形成 j 种字母的方案数
#include<bits/stdc++.h>
using namespace std;
int mod = 1e9+7;
long long mypow(int a, int b){
    long long res = 1;
    for (int i=0; i < b; i++){
        res = res*a % mod;
    }
    return res;
}
int main(){
    int n , k;
    cin >> n >> k;
    string str;
    cin >> str;
    vector<int> hash(26, 0);
    for (int i=0; i < str.size(); i++){
        hash[str[i] - 'a'] ++;
    }
    vector<long long> v(26,0);
    for (int i=0; i < 26; i++){
        if (hash[i] != 0)
            v[i] = mypow(2, hash[i]) - 1; //该字母可以形成的非空子序列的数量
    }
    vector<long long> dp(k+1, 0);
    dp[0] = 1;
    for(int i=0; i < 26; i++){
        for(int j=k; j >= 1; j--){
            dp[j] = (dp[j] + dp[j-1] * v[i])%mod;
        }
    }
    cout << dp[k] << endl;
}

 

posted @ 2025-07-10 11:38  最近饭吃的很多  阅读(13)  评论(0)    收藏  举报