题目描述

给定一个长度为2021-09-07-19:00-21:00百度后端笔试第三题(好题_百度的字母序列,求包含恰好有2021-09-07-19:00-21:00百度后端笔试第三题(好题_动态规划_02种字母的子序列的数量,答案对2021-09-07-19:00-21:00百度后端笔试第三题(好题_百度_03取模。
例如:

输入
6 5
eecbad
输出
3
输入
10 2
aaaccebecd
输出
126

思路

个人觉得这个是个极好的题,我们发现对于每个字母的贡献考虑组合数,设字母2021-09-07-19:00-21:00百度后端笔试第三题(好题_动态规划_04出现的次数是2021-09-07-19:00-21:00百度后端笔试第三题(好题_背包问题_05,那么贡献就是2021-09-07-19:00-21:00百度后端笔试第三题(好题_动态规划_06(因为2021-09-07-19:00-21:00百度后端笔试第三题(好题_i++_07),所以我们可以类比背包问题,将这个贡献当作价值2021-09-07-19:00-21:00百度后端笔试第三题(好题_i++_08,重量赋2021-09-07-19:00-21:00百度后端笔试第三题(好题_i++_092021-09-07-19:00-21:00百度后端笔试第三题(好题_动态规划_10,背包容量是2021-09-07-19:00-21:00百度后端笔试第三题(好题_动态规划_02,令2021-09-07-19:00-21:00百度后端笔试第三题(好题_百度_12表示取2021-09-07-19:00-21:00百度后端笔试第三题(好题_动态规划_04种字母的方案数,从而求解。

代码

#include <bits/stdc++.h>
using namespace std;

const int N = 1e5 + 5;
long long dp[26];
const long long mod = 1e9 + 7;
char s[N];
long long qpow(long long a, long long b)
{
long long res = 1;
while (b)
{
if (b & 1)
{
res = res * a % mod;
}
b /= 2;
a = a * a % mod;
}
return res;
}
int v[30];
int w[30];
void solve()
{
int n, k;
cin >> n >> k;
scanf("%s", s + 1);
map<char, int> mp;
for (int i = 1; i <= n; i++)
mp[s[i]]++;
for (char i = 'a'; i <= 'z'; i++)
{
v[i - 'a'] = qpow(2, mp[i]) - 1;
w[i - 'a'] = 1;
}
dp[0] = 1;
for (int i = 0; i < 26; i++)
{
for (int j = k; j >= 1; j--)
{
if (j >= w[i])
{
dp[j] = (dp[j] + dp[j - w[i]] * v[i]) % mod;
}
}
}

cout << dp[k] << endl;
}
int main()
{
solve();

return 0;
}