C. K-beautiful Strings(贪心+思维)
题意:给你一个字符串长度为N,再给你一个K。要求字符串中每个字符出现的总数是K的倍数,如果不是K的倍数,那么就修改字符串,修改后的字符串比原字符串大,而且输出大于原字符串的最小字符串。
例:
15 3
a b c c c c b b a b c c c c a
a b c c c c b b a c a a a a c
题解:如上述样例第十个字符变成c,后面的变成a然后补充c,这个过程是怎么来的?首先我们应该先处理每个字符的总数,因为修改字符串必然是修改从最后面字符往前修改才会得到最小的,如何修改呢,必然是找到某一个位置然后将当前位置的字符变成下一位字母,然后后面的再用a来补,最后补上原来不用删的的字符。
从后面往前面开始处理,处理的关键是:sum+=(k-vis[i]%k)%k,这个sum代表所有需要变化的字符总数,判断当前是否处理的依据是:sum<=n-i,代表当前处理的字符数小于等于当前i位的字符到n-1位的字符长度,这样这个字符才有足够的长度去变化,当前位置的(赋值一个新的)num=sum变成减去当前位置差的字符个数,然后当前字符vis[ss[i]-‘a’]]- -,再次加上需要 (k-(vis[ss[i]-‘a’])%k)%k增加的个数,最后判断新sum+i <=n那么就可以去变化更新字符,当前位置的字符变成后一位字符,后面的就变成然后之后有剩余的就遍历一下 最后输出需要的就可以了,注意特判N%K!=0的时候,必然是不可以成立的条件,还有特判1。
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define fio ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
#define mse(a,b) memset(a,b,sizeof a)
#define pb push_back
#define pii pair<int,int>
using namespace std;
const int mod=1e9+7;
const int maxx=1e6+10;
const double eps=1e-6;
using namespace std;
const long double PI = 3.14159265358979323846;
//inline ll read(){ ll x=0,f=1; char ch=getchar(); while (!isdigit(ch)) { if (ch=='-') f=-1; ch=getchar(); } while (isdigit(ch)) { x=x*10+ch-48; ch=getchar(); } return x*f;}
//ll cc = ((1ll << 62) - 1 + (1ll << 62));
/*struct node {
ll l,r ,lazy,val;
node() :l(),r(),lazy(),val(){}
node(ll a, ll b, ll c,ll d) :l(a),r(b),lazy(c),val(d){}
};*/
int vis[30];
int n,k;
int get(int x){
return (k-(x%k))%k; //计算当前字符是k的倍数
}
signed main()
{
int t;cin>>t;
while(t--){
cin>>n>>k; string ss; cin>>ss;
if(n%k) cout<<-1<<'\n'; ///特判
else{ bool flag=false; mse(vis,0); int sum=0; //初始化
for(int i=0;i<n;i++) vis[ss[i]-'a']++; //预处理每个字符的个数
for(int i=0;i<26;i++) sum+=get(vis[i]); //初始计算需要改变多少个字符
if(sum==0) cout<<ss<<endl;
else{
for(int i=n-1;i>=0;i--){ //从后往前边遍历每个字符
sum-=get(vis[ss[i]-'a']); //当前位置的字符 先剪掉所有的
vis[ss[i]-'a']--; ///去除掉当前位置的字符
sum+=get(vis[ss[i]-'a']); //重新计算去除当前的字符后,还需要多少个当前字符才是K的倍数(有可能去除之后的就是K的倍数了)
if(sum>n-i) continue;///后面修改的位置够了
for(int j=ss[i]-'a'+1;j<26;j++){ //枚举
int num=sum; ///赋值
num-=get(vis[j]);
vis[j]++;
num+=get(vis[j]); //枚举计算
if(num+i<=n){ //符合修改
for(int kk=0;kk<i;kk++)cout<<ss[kk]; //直接输出区间[0-i-1]前面不变的字符
cout<<char(j+'a'); //输出第i位的改变的字符
for(int kk=i+1;kk<n-num;kk++) cout<<'a';
for(int kk=0;kk<26;kk++)
{
int pp=get(vis[kk]);
while(pp--) cout<<char(kk+'a');
}
cout<<endl;
flag=true;
}
if(flag) break;
vis[j]--;
}
if(flag) break;
}
}
}
}
return 0;
}