【每日一题】ABC202D - aab aba baa | 组合数 | 简单

题目内容

原题链接

给定 a a a'a' b b b'b' ,求由这 a + b a+b a+b 个字符组成的字典序第 k k k 大字符串。

数据范围

  • 1 ≤ a , b ≤ 30 1\leq a,b\leq 30 1a,b30
  • 1 ≤ k ≤ S 1\leq k\leq S 1kS, S S S 是这 a + b a+b a+b 个字符组成的不同字符串的数量

题解

考虑当前还有 x x x'a' y y y'b' ,尝试当前位安排 'a'

  • 如果 C a + b − 1 a − 1 > k C_{a+b-1}^{a-1}> k Ca+b1a1>k ,说明如果安排了 'a' ,则凑成的最大的字符串也比第 k k k 大的字典序小,所以应该安排 'b'
  • 如果 C a + b − 1 a − 1 ≤ k C_{a+b-1}^{a-1}\leq k Ca+b1a1k,说明应该安排 'a'

此外,如果没有 'a' 了,那么说明后续都得安排 'b'

时间复杂度: O ( ( a + b ) × b ) O((a+b)\times b) O((a+b)×b)

代码

#include 
using namespace std;

typedef long long ll;
ll get_cnt(int n, int a) {
    ll res = 1;
    for (int i = 1, j = n; i <= a; ++i, --j) {
        res = res * j / i;
    }
    return res;
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int a, b;
    ll k;
    cin >> a >> b >> k;

    int n = a + b;
    string ans(n, 'b');

    for (int i = 0; i < n && a > 0; ++i) {
        ll cnt = get_cnt(a + b - 1, a - 1);
        if (k > cnt) {
            k -= cnt;
            ans[i] = 'b';
            b -= 1;
        } else {
            ans[i] = 'a';
            a -= 1;
        }
    }

    cout << ans << "\n";

    return 0;
}

你可能感兴趣的:(算法竞赛,算法,组合数)