题目链接:
https://codeforces.com/problemset/problem/1620/C
题目大意:
给定一个数 \(k\) 和一个由 'a' 和 * 构成的长为 \(n\) 的字符串,字符串中每一个 * 可以被 0 到 \(k\) 个 'b' 替换,要求输出第 \(x\) 小的字符串。
思路:
字符串从小到大的话,可以想到 从右往左 用 'b' 填充 *,这样子就可以实现从小到大去数第 \(x\) 个字符串。
将 'a' 隔开的 * 的字符串记录下来,从右往左标记为 \(s_1\),\(s_2\),\(s_3\)...,同时记每个字符串对应的长度为 \(cnt_1\),\(cnt_2\),\(cnt_3\)...,那么 \(s_1\) 包含了 \(cnt_1 * k + 1\) 种填充方式,即第 0 大到第 \(cnt_1 * k\) 小的字符串,所以开始的 \(x\) 要减 1。第 \(s_2\) 中每填一个 'b' 都会有 \(cnt_1 * k + 1\) 种方式
(因为它右边的 * 字符串有 \(cnt_1 * k + 1\) 种,以此类推,最后第 \(i\) 段字符串有 \((cnt_1 * k + 1) * (cnt_2 * k + 1) * ... * (cnt_{i - 1} * k + 1) * (cnt_i * k + 1)\) 种方案。)
第 \(i\) 段要放的 'b' 就是 \(x\) % \((cnt_i * k + 1)\) ,因为从右向左填充,所以每一段填充后,使 \(x\) 变为 \(x / (cnt * k + 1)\)。
代码:
#include <bits/stdc++.h>
using namespace std;
#define LL long long
LL T, n, k, x;
string s;
void solve(){
cin >> n >> k >> x >> s;
reverse(s.begin(), s.end());
string ans = "";
int cnt = 0;
x--;
for (int i = 0; i < n; i++){
if (s[i] == 'a'){
LL cur = cnt * k + 1;
ans += string(x % cur, 'b') + 'a';
x /= cur;
cnt = 0;
}
else
cnt++;
}
ans += string(x % (cnt * k + 1), 'b');
reverse(ans.begin(), ans.end());
cout << ans << "\n";
}
int main(){
cin >> T;
while(T--)
solve();
return 0;
}