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[A1][B]

k ≤ f [ A − 1 ] [ B ] k\\le f[A-1][B] kf[A1][B],那么显然当前字典序的前 f [ A − 1 ] [ B ] f[A-1][B] f[A1][B] 个字符串都是以 a a a 开头的, k ≤ f [ A − 1 ] [ B ] k\\le f[A-1][B] kf[A1][B],所以我们这一位一定是 a a a

k > f [ A − 1 ] [ B ] k>f[A-1][B] k>f[A1][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[A1][B] 的字符串了,所以排名第 k k k 的字符串就变成了排名第 k − f [ A − 1 ] [ B ] k-f[A-1][B] kf[A1][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 234

AtCoder Beginner Contest 115 题解

AtCoder Beginner Contest 154 题解

AtCoder Beginner Contest 103

AtCoder Beginner Contest 228

AtCoder Beginner Contest 242