Codeforces Round #705 (Div. 2) C. K-beautiful Strings

C. K-beautiful Strings

题意

给一个长度为 n ( 1 ≤ n ≤ 1 0 5 ) n(1\le n \le 10^5) n(1n105) 的字符串,要求找到字典序最小且字典序大于等于当前字符串的长度为 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:;
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_43860866/article/details/114890804
今日推荐