小易在学校中学习了关于字符串的理论, 于是他基于此完成了一个字典的项目。
小易的这个字典很奇特, 字典内的每个单词都包含n个’a’和m个’z’, 并且所有单词按照字典序排列。
小易现在希望你能帮他找出第k个单词是什么。
输入描述
输入包括一行三个整数 \(n, m, k(1 \leq n, m \leq 100, 1 \leq k \leq 10^9)\), 以空格分割。
输出描述
输出第 \(k\) 个字典中的字符串,如果无解,输出-1。
示例1
输入
2 2 6
输出
zzaa
说明
字典中的字符串依次为aazz azaz azza zaaz zaza zzaa
解析
假设单词为例题中的情况,当第一个为 \(a\) 时,则 \(a\) 后面有 \(n-1\) 个 \(a\) 和 \(m\) 个 \(z\),其全排列的情况为 \(\mathrm{C}_{n+m-1}^{n-1}\),当 \(\mathrm{C}_{n+m-1}^{n-1} \geq k\) 时,则代表第一个为 \(a\) 的情况就包含了所要求的第 \(k\) 个单词,也包含了前 \(\mathrm{C}_{n+m-1}^{n-1}\) 个单词;当\(\mathrm{C}_{n+m-1}^{n-1} \lt k\) 时,则代表第一个为 \(a\) 不能找到第 \(k\) 个单词,因此第一个一定为 \(z\);以此为循环直到当 \(a\) 或者 \(z\) 已经使用完为止。
循环完之后,因为剩下的只有一种排列情况了,所以 \(t\) 一定为1,此时如果 \(k \gt 1\) 则代表所要找的单词超出了所要找的单词量。
#include <iostream>
#include <vector>
using namespace std;
long long total(int n, int m, int k) {
if (n == 0 || m == 0) return 1;
int b = (n > m) ? n : m;
int s = n + m - b;
// 排列组合:假设当前序列首字符为a,剩下n-1个a放在剩下n-1+m个位置共有的可能数
long long count = 1;
for (int i = 0; i < n; i++) {//求组合数
count *= n + m - i;
count /= (i + 1);
if (count > k) break; //防止越界。count>k就可以退出计算了
}
return count;
}
int main() {
int n, m;
long long k;
cin >> n >> m >> k;
int len = n + m;
string ans = "";
while (n > 0 && m > 0) {
// 假设当前下标是a
long long t = total(n - 1, m, k);
// printf("%d %d %lld %lld\n", n, m, t, k);
if (k <= t) {
ans += 'a';
n--;
} else if (k > t) { // 当前下标不能为a,因为所需要的k超过了前面的所有情况
ans += 'z';
m--;
k -= t;
}
}
if (k > 1) {
cout << -1 << endl;
return 0;
}
while (n--) ans += 'a';
while (m--) ans += 'z';
cout << ans << endl;
return 0;
}