Codeforce-K-beautiful Strings

7 篇文章 0 订阅
3 篇文章 0 订阅

K-beautiful Strings

题目描述

You are given a string s consisting of lowercase English letters and a number k. Let’s call a string consisting of lowercase English letters beautiful if the number of occurrences of each letter in that string is divisible by k. You are asked to find the lexicographically smallest beautiful string of length n, which is lexicographically greater or equal to string s. If such a string does not exist, output −1.
A string a is lexicographically smaller than a string b if and only if one of the following holds:

  1. a is a prefix of b, but a≠b;
  2. in the first position where a and b differ, the string a has a letter that appears earlier in the alphabet than the corresponding letter in b.

输入

The first line contains a single integer T (1≤T≤10000) — the number of test cases.
The next 2⋅T lines contain the description of test cases. The description of each test case consists of two lines.
The first line of the description contains two integers n and k (1≤k≤n≤105) — the length of string s and number k respectively.
The second line contains string s consisting of lowercase English letters.
It is guaranteed that the sum of n over all test cases does not exceed 105.

输出

For each test case output in a separate line lexicographically smallest beautiful string of length n, which is greater or equal to string s, or −1 if such a string does not exist.

Sample Input

4
4 2
abcd
3 1
abc
4 3
aaaa
9 3
abaabaaaa

Sample Output

acac
abc
-1
abaabaaab

Hint

In the first test case “acac” is greater than or equal to s, and each letter appears 2 or 0 times in it, so it is beautiful.
In the second test case each letter appears 0 or 1 times in s, so s itself is the answer.
We can show that there is no suitable string in the third test case.
In the fourth test case each letter appears 0, 3, or 6 times in “abaabaaab”. All these integers are divisible by 3.

题目大意

n代表字符串长度,m代表整除的数字。给定一个字符串,要求其中的每一个字母的个数都满足cnt[char]%m==0,那么这个字符串就叫做Beautiful String。例如 n=6 m=3 “aaabbb”。如果n=6 m=2 aaabbb就不是。
现在我们要求,你构造出一个不比这个字符串字典序要小,且最小的Beautiful String。注意长度不能变

解题思路

如果这题是告诉你从第i位往后删除,且长度不变,构造出Beautiful String 这题就是个水题了。
比如 n=6 m=2 “abcdef”从第3位往后重新构造 abcxxx 构造成abcabc就行了呗。没错,构造就这么简单。但是这里要做一些变化。
首先要不比原字符串的字典序要小。那么我们要这么构造。abdabd便是了,在前一位比原先大一位。OK,知道了构造方法,那么这题就很容易了。

回归这道题。如果说,本身就是个Beautiful String那么,这个串不需要处理,直接输出便是。
这里我们计算一下,每一个类型的字符,需要补充多少可以构成一个可以被m整除的数,我们很容易发现,这些需要补充的数字加和一定是可以被m整除的,否则就是无解。
这里的本质就是转移,如果我们可以把需要转移给其余的,让其余的多出来的抵消,这样理论上来说,多余和需要应该是相同的,当然这里的需要和多余都是相对的概念,总而言之的意义是,他们可以相互转换,都转换为一种字符。这样看看这个字符是否能整除就行了,如果能整除的话,说明这一定能够造出来了但不一定最优。
如果没有办法加整除,那么就一定无法构造出相对应的解。

对于寻求解,我们尽力保证原字符串不做变化,从后向前找,这样能构造出最优解的Beautiful String。
我们枚举每一位所替换的字母,因为我们构造的思路是,让某一位变的稍微大一点,后面的都可以任意修改。总有一个字母会比之前大,那么我们让这个字母稍微靠后这是最优的。
当我发现,剩下的字母需补充的和正好和空下的位置(abcxxxx)相同的时候,我们就意识到这就可以直接构造了。构造结束后直接输出,因为我们是从最小的字典序寻找的结果嘛。不过这里有个问题
如果m=3 xxxxxxx…… 里原本有很多的字母※,且正好是m的倍数,那么会统计出,字母※需要补充0个,这就导致了,可能不够原先字符串的长度,这里我们就输出ASCII码最小的a补全就好了。然后后面照常构造。
思路清晰,分析完毕。

代码

//#include<unordered_map>
#include<algorithm>
#include<iostream>
#include<string.h>
#include <iomanip>
#include<stdio.h>
#include<vector>
#include<string>
#include<math.h>
#include<cmath>
#include<queue>
#include<stack>
#include<deque>
#include<map>
#include<set>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const ll ll_inf = 9223372036854775807;
const int int_inf = 2147483647;
const short short_inf = 32767;
const ll less_inf = 0x3f3f3f3f;
const char char_inf = 127;
#pragma GCC optimize(2)
#define accelerate cin.tie(NULL);cout.tie(NULL);ios::sync_with_stdio(false);
#define PI 3.141592653589793
#define EPS 1.0e-8
ll gcd(ll a, ll b) {
	return b ? gcd(b, a % b) : a;
}
ll lcm(ll a, ll b) {
	return a * b / gcd(a, b);
}
inline ll read() {
	ll c = getchar(), Nig = 1, x = 0;
	while (!isdigit(c) && c != '-')c = getchar();
	if (c == '-')Nig = -1, c = getchar();
	while (isdigit(c))x = ((x << 1) + (x << 3)) + (c ^ '0'), c = getchar();
	return Nig * x;
}
inline void out(ll a) {
	if (a < 0)putchar('-'), a = -a;
	if (a > 9)out(a / 10);
	putchar(a % 10 + '0');
}
ll qpow(ll x, ll n, ll mod) {
	ll res = 1;
	while (n > 0) {
		if (n & 1)res = (res * x) % mod;
		x = (x * x) % mod;
		n >>= 1;
	}
	return res;
}
#define read read()
char save[100005];
int cnt[128];
int main()
{
	int T = read;
	while (T--)
	{
		memset(cnt, 0, sizeof(cnt));
		int sum = 0;
		int n = read, m = read;
		scanf("%s", save);
		for (int i = 0; save[i]; i++)cnt[save[i]]++;
		for (int i = 'a'; i <= 'z'; i++)
			sum += (m - cnt[i] % m) % m;
		if (sum == 0)puts(save);
		else if (sum % m)puts("-1");
		else
		{
			for (int i = n - 1; i >= 0; i--)
			{
				sum -= (m - cnt[save[i]]-- % m) % m;
				sum += (m - cnt[save[i]] % m) % m;
				for (int j = save[i] + 1; j <= 'z'; j++)
				{
					int LastSum = sum;
					sum -= (m - cnt[j]++ % m) % m;
					sum += (m - cnt[j] % m) % m;
					if (i + 1 + sum <= n)
					{
						for (int k = 0; k < i; k++)putchar(save[k]);
						putchar(j);
						for (int k = i + 1 + sum; k < n; k++)
							putchar('a');
						for (char k = 'a'; k <= 'z'; k++)
						{
							int tot = (m - cnt[k] % m) % m;
							while (tot--)putchar(k);
						}
						puts("");
						goto END;
					}
					else cnt[j]--, sum = LastSum;
				}
			}
		}
	END:;
	}
	return 0;
}

By-Round moon

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Round moon

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值