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;
}
posted @ 2021-05-25 21:03  Jude_Zhang  阅读(105)  评论(0编辑  收藏  举报