小易的字典

版权声明:本文为博主原创文章,遵循 CC 4.0 BY 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/cpongo3/article/details/98207095

小易在学校中学习了关于字符串的理论, 于是他基于此完成了一个字典的项目。

小易的这个字典很奇特, 字典内的每个单词都包含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;
}
展开阅读全文

没有更多推荐了,返回首页