C. K-beautiful Strings
题意
给一个长度为 n ( 1 ≤ n ≤ 1 0 5 ) n(1\le n \le 10^5) n(1≤n≤105) 的字符串,要求找到字典序最小且字典序大于等于当前字符串的长度为 n n n 的字符串,满足所有字母出现次数被 k k k 整除。
题解
- 如果 n n n 不是 k k k 的倍数,那么答案显然不存在,否则答案一定存在;
- 首先检查自身是否符合条件,如果不符合,从后往前贪心。每次把当前遍历到的字母加一,这时候后面的字符就是任意的,结合前缀检查是否可能满足条件;
- 如果可以满足条件,计算出每个字母缺什么,在后面按照字典序补足即可。
代码
#pragma region
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <vector>
using namespace std;
typedef long long ll;
#define rep(i, a, n) for (int i = a; i <= n; ++i)
#define per(i, a, n) for (int i = n; i >= a; --i)
#pragma endregion
const int maxn = 1e5 + 5;
char s[maxn];
int n, k;
int pre[maxn][26];
bool check(int len) {
vector<int> ned(26);
int sum = 0;
rep(i, 0, 25) ned[i] = (k - pre[len][i] % k) % k, sum += ned[i];
if (sum > n - len) return 0;
rep(i, 1, len) putchar(s[i]);
rep(i, 1, n - len - sum) putchar('a');
rep(i, 0, 25) while (ned[i]--) putchar('a' + i);
puts("");
return 1;
}
int main() {
int T;
scanf("%d", &T);
while (T--) {
scanf("%d%d%s", &n, &k, s + 1);
if (n % k) {
puts("-1");
continue;
}
rep(i, 1, n) rep(j, 0, 25) pre[i][j] = pre[i - 1][j] + (s[i] == 'a' + j);
if (check(n)) continue;
per(i, 1, n) {
while (s[i] < 'z') {
pre[i][s[i] - 'a']--;
++s[i];
pre[i][s[i] - 'a']++;
if (check(i)) goto en;
}
}
en:;
}
}