AISing Programming Contest 2021(AtCoder Beginner Contest 202)D题题解

D - aab aba baa

题面

Among the strings of length (A + B) containing (A) occurrences of a and (B) occurrences of b, find the string that comes (K)-th in the lexicographical order.

题面意思是给定(A)a(B)b所组成的字符串,问若按字典序排列这个字符串,则按照从小到大第(K)个字典序的字符串表示是什么。

样例解释:

2 2 4

两个a和两个b组成的字符串的字典序从小到大为: aabb, abab, abba, baab, baba, bbaa
第四个为baab,即答案为baab

解题思路

只有'a','b'两个字母,且跟排列有关,于是想试试他的K值是否与组合数有关。

最后找到了如下关系:

(根据高中数学 (C_{a+b}^{a})的值即为所有组合情况)

cur表示能构造出前cur个字典序,初始化为0(现在不能理解没有关系)
设输入的a为剩余a的数量
设输入的b为剩余b的数量
设输入的k为第k个字典序字符串

现在假设按样例输入

2 2 4

一共四位值,则假设第一位值是a,
那么现在所有的组合数为 (C_{a+b-1}^{a-1})

(d=C_{a+b-1}^{a-1})

则 d + cur 为能覆盖到的字典序(d+cur及之前的字典序都能实现)

(d + cur >= k) 则说明第一位为a的情况下,a这个位置满足条件,后面可以继续构造)
否则说明当前位不能为a,则输b然后cur += d。

代码如下

#include <iostream>

using namespace std;

typedef long long ll;
const int N = 100;

ll q[N][N];


/* 求组合数 */
void solve ( void )
{
    for ( int i = 0; i < N; i++ )
    {
        for ( int j = 0; j <= i; j++ )
        {
            if ( !j )
            {
                q[i][j] = 1;
                continue;
            }

            q[i][j] = q[i - 1][j] + q[i - 1][j - 1];
        }
    }
}

ll C ( ll a, ll b )
{
    return q[a][b];
}

int main ( void )
{
    solve();	/* 预处理组合数 */

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

    for ( ll m = a + b, i = 0, cur = 0; i < m; i++ )
    {
        ll d = C( a + b - 1, a - 1 );

        if ( a == 0 ) cout << 'b';
        else if ( b == 0 ) cout << 'a';
        else if ( k <= cur + d ) cout << 'a', a--;
        else cout << 'b', b--, cur = min ( k, cur + d );
    }

    return 0;
}
作者:Jude_Zhang
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用BY-NC-SA 许可协议。转载请注明出处!
支持博主:如果您觉得文章对您有帮助,可以点击文章下方赞一下。您的鼓励是博主的最大动力!
原文地址:https://www.cnblogs.com/judezhang/p/14810546.html