chenfy27的刷题记录

导航

abc202D aab aba baa

由x个a和y个b构成长度为x+y的字符串,求字典序第k小的那个串。
1<=x,y<=30; 保证k有效。

思路:x个a和y个b能构成的不同字符串有\(f(x,y)= \frac{(x+y)!}{x!y!}\)个。从左到右枚举各个字符,假设当前还剩x个a和y个b,如果放a,后续有f(x-1,y)种;如果放b,后续有f(x,y-1)种。将k与f(x-1,y)比较大小决定走哪个分支即可。

#include <bits/stdc++.h>
using i64 = long long;

std::vector<int> minp, prime;
void sieve(int n) {
	minp.assign(n + 1, 0);
	prime.clear();
	for (int i = 2; i <= n; i++) {
		if (minp[i] == 0) {
			minp[i] = i;
			prime.push_back(i);
			for (int j = 2 * i; j <= n; j += i) {
				if (minp[j] == 0) {
					minp[j] = i;
				}
			}
		}
	}
}

std::map<int,int> factorial(int x) {
    std::map<int,int> mp;
    for (int i = 2; i <= x; i++) {
        for (int j = i; minp[j] > 1; j /= minp[j])
            mp[minp[j]] += 1;
    }
    return mp;
}
i64 f(int x, int y) {
    std::map<int,int> mp = factorial(x + y);
    for (auto [k, v] : factorial(x)) {
        mp[k] -= v;
    }
    for (auto [k, v] : factorial(y)) {
        mp[k] -= v;
    }
    i64 ans = 1;
    for (auto [k, v] : mp) {
        for (int i = 1; i <= v; i++) {
            ans *= k;
        }
    }
    return ans;
}
void solve() {
    int a, b;
    i64 k;
    std::cin >> a >> b >> k;
    int cnt = a + b;
    for (int i = 1; i <= cnt; i++) {
        if (a > 0 && k <= f(a - 1, b)) {
            std::cout << 'a';
            a -= 1;
        } else {
            std::cout << 'b';
            k -= f(a - 1, b);
            b -= 1;
        }
    }
}

int main() {
    sieve(60);
    std::cin.tie(0)->sync_with_stdio(0);
    int t = 1;
    while (t--) solve();
    return 0;
}

posted on 2024-03-09 20:36  chenfy27  阅读(19)  评论(0)    收藏  举报