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 许可协议。转载请注明出处!
支持博主:如果您觉得文章对您有帮助,可以点击文章下方赞一下。您的鼓励是博主的最大动力!
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用BY-NC-SA 许可协议。转载请注明出处!
支持博主:如果您觉得文章对您有帮助,可以点击文章下方赞一下。您的鼓励是博主的最大动力!