AtCoder Beginner Contest 202 D - aab aba baa(组合计数,字典序)
Posted 繁凡さん
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了AtCoder Beginner Contest 202 D - aab aba baa(组合计数,字典序)相关的知识,希望对你有一定的参考价值。
整理的算法模板合集: ACM模板
实际上是一个全新的精炼模板整合计划
Problem
有 A A A 和 a a a, B B B 个 b b b ,可以使用这 A + B A+B A+B 个字符任意组合成一个长度为 A + B A+B A+B 的字符串,问组成的所有字符串中,按字典序排列的第 k k k 个字符串是啥。
Solution
没打这场比赛,有人QQ问我这题来着,然后就爬过来写题解了。
显然 A A A 和 a a a, B B B 个 b b b ,任意排列为多重集的全排列,方案数为 ( A + B ) ! A ! B ! \\cfrac{(A+B)!}{A!B!} A!B!(A+B)!。
当然数据较大,直接求阶乘没有模数要爆 long long
,所以我们可以将问题转换为模型:从
(
0
,
0
)
(0,0)
(0,0),出发,每次可以向右移动一步,或者向上移动一步,移动到
(
A
,
B
)
(A, B)
(A,B) 的方案数
f
[
A
]
[
B
]
f[A][B]
f[A][B],直接DP转移即可。
询问的是字典序第 k k k 的字符串是啥,考虑按顺序分配字符。显然 a a a 开头的字符串字典序小于 b b b 开头的字符串,对于当前的 A A A 和 a a a, B B B 个 b b b ,按照字典序,以 a a a 开头的字符串一定都小于以 b b b 开头的字符串,因为我们要求的是第 k k k 大,显然按照顺序来,先考虑以 a a a 开头的字符串的方案数,即固定第一个字符一定是 a a a,剩下的随意,那么方案数就为 f [ A − 1 ] [ B ] f[A-1][B] f[A−1][B]。
若 k ≤ f [ A − 1 ] [ B ] k\\le f[A-1][B] k≤f[A−1][B],那么显然当前字典序的前 f [ A − 1 ] [ B ] f[A-1][B] f[A−1][B] 个字符串都是以 a a a 开头的, k ≤ f [ A − 1 ] [ B ] k\\le f[A-1][B] k≤f[A−1][B],所以我们这一位一定是 a a a。
若 k > f [ A − 1 ] [ B ] k>f[A-1][B] k>f[A−1][B],那么 a a a 开头字符串个数也不够分呐,所以只能以 b b b 开头,这一位是 b b b,这样就不会有以 a a a 开头的 A A A 和 a a a, B B B 个 b b b 这些 f [ A − 1 ] [ B ] f[A-1][B] f[A−1][B] 的字符串了,所以排名第 k k k 的字符串就变成了排名第 k − f [ A − 1 ] [ B ] k-f[A-1][B] k−f[A−1][B] 的字符串。
递归子问题处理即可。
Code
// Problem: D - aab aba baa
// Contest: AtCoder - AISing Programming Contest 2021(AtCoder Beginner Contest 202)
// URL: https://atcoder.jp/contests/abc202/tasks/abc202_d
// Memory Limit: 1024 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1e3 + 7;
int f[N][N];
int a, b, k;
string Find(int A, int B, int k)
{
if(A == 0) return string(B, 'b');
if(B == 0) return string(A, 'a');
if(k <= f[A - 1][B]) {
string s = "a";
return s + Find(A - 1, B, k);
}
else {
string s = "b";
return s + Find(A, B - 1, k - f[A - 1][B]);
}
}
signed main()
{
scanf("%lld%lld%lld", &a, &b, &k);
f[0][0] = 1;
for(int i = 0; i <= a; ++ i) {
for(int j = 0; j <= b; ++ j) {
if(i > 0)
f[i][j] += f[i - 1][j];
if(j > 0)
f[i][j] += f[i][j - 1];
}
}
cout << Find(a, b, k) << endl;
return 0;
}
以上是关于AtCoder Beginner Contest 202 D - aab aba baa(组合计数,字典序)的主要内容,如果未能解决你的问题,请参考以下文章
AtCoder Beginner Contest 115 题解