题目
LCP 25. 古董键盘
小扣在秋日市集购买了一个古董键盘。由于古董键盘年久失修,键盘上只有 26 个字母 a~z 可以按下,且每个字母最多仅能被按 k 次。
小扣随机按了 n 次按键,请返回小扣总共有可能按出多少种内容。由于数字较大,最终答案需要对 1000000007 (1e9 + 7) 取模。
示例 1:
输入:k = 1, n = 1
输出:26
解释:由于只能按一次按键,所有可能的字符串为 "a", "b", ... "z"
示例 2:
输入:k = 1, n = 2
输出:650
解释:由于只能按两次按键,且每个键最多只能按一次,所有可能的字符串(按字典序排序)为 "ab", "ac", ... "zy"
提示:
1 <= k <= 5
1 <= n <= 26*k
题解
动态规划:
- 用dp[i][j]表示长度为i,使用前j个字母能按出的字串总数。假设第j个字母按了x次(x取值范围为0~k),那么:
C(i, x)表示i个位置中选择x个位置有多少种方式。 - C(n,m)计算方式:
C++代码
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const ll mod = 1000000007;
class Solution {
public:
int keyboard(int k, int n) {
vector<vector<ll>> dp(n + 1, vector<ll>(27, 0L));
for (int j = 0; j <= 26; ++j) {
dp[0][j] = 1;
}
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= 26; ++j) {
for (int x = 0; x <= k; ++x) {
if (i >= x) {
dp[i][j] += dp[i - x][j - 1] * C(i, x);
}
}
dp[i][j] %= mod;
// cout << i << "," << j << ":" << dp[i][j] << endl;
}
}
return dp[n][26];
}
ll C(int n, int m)
{
ll fz = 1;
ll fm = 1;
for (int i = n; i >= n - m + 1; --i) {
fz *= i;
}
for (int j = m; j >= 2; --j) {
fm *= j;
}
return fz / fm;
}
};