子序列中的 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; }
浙公网安备 33010602011771号