K-beautiful Strings

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:

a is a prefix of b, but a≠b;
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.

Input
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.

Output
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.

Example
inputCopy
4
4 2
abcd
3 1
abc
4 3
aaaa
9 3
abaabaaaa
outputCopy
acac
abc
-1
abaabaaab

Note
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.

题意
beautiful Strings:串中各个字母的个数能被m整除
求字典序最小的beautiful Strings(比原串大)

思路
从后往前暴力枚举,比如当前位置是k,则枚举范围(str[k]-‘a’+1, 26),对于每一次枚举,把串分成前半部分(0, k)和后半部分(k, n-1),计算前半部分各个字母被m整除所需的数量的和sum,如果sum与后半部分的串长相等(sum=n-1-k) 或者 小于后半部分的串长但是相减后得到的数字也能被m整除(sum<=n-k-1 && (n-k-1-sum)%m=0),即为答案,之后只要按照字母升序(a-z)跑一边,依次加入各个字母所需数量的字母,就是答案,否则-1

代码

#include <bits/stdc++.h>
using namespace std;
 
int n, m;
int s[100005][30];
string str;
int a, b, cnt;
 
bool check(int nw, int k){
	s[nw][str[nw]-'a']--;
	s[nw][k]++;
	int sum=0;
	for(int i=0;i<26;++i){
		if(s[nw][i]%m)
			sum+=m-s[nw][i]%m;
	}
	s[nw][str[nw]-'a']++;
	s[nw][k]--;
	if(sum<=n-nw-1 && (n-nw-1-sum)%m==0){
		cnt=(n-nw-1)-sum;
		return true;
	}
	return false;
}
 
bool work(){
	for(int i=n-1;i>=0;--i)
		for(int j=str[i]-'a'+1;j<26;++j)
			if(check(i, j)){
				a=i, b=j; //a, b 用于记录最先符合题目要求的位置
				return true;
			}
	return false;
}
 
void output(){
	//cout<<a<<' '<<b<<endl;
	s[a][str[a]-'a']--;
	s[a][b]++;
	str[a]='a'+b;
	int nw=a;
	//cout<<cnt<<endl;
	while(cnt) str[++nw]='a', cnt--; 
	for(int i=0;i<26;++i){
		if(s[a][i]%m){
			int en=m-s[a][i]%m;
			for(int j=1;j<=en;++j) str[++nw]='a'+i;
		}
	}
	cout<<str<<endl; 
}
 
int main(){
	int T; cin>>T;
	while(T--){
		cin>>n>>m;
		cin>>str;
		if(n%m){ // 如果n%m>0 肯定就不行了
			cout<<-1<<endl;
			continue;
		}
		memset(s[0], 0, sizeof(s[0]));
		s[0][str[0]-'a']++;
		for(int i=1;i<n;++i){ //类似于前缀和,提前记录前半串的各字母数量
			for(int j=0;j<26;++j) s[i][j]=s[i-1][j];
			s[i][str[i]-'a']++;
		}
		bool sum=0;
		for(int i=0;i<26;++i)
			if(s[n-1][i]%m) sum=1;
		if(!sum){ // 如果已经符合直接输出
			cout<<str<<endl;
			continue;
		}
		cnt=0; // 如果该条件(sum<=n-k-1 && (n-k-1-sum)%m=0)符合,则cnt记录多出来的字母个数
		if(work()) output();
		else cout<<-1<<endl;
	}
 
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值