题目链接:https://codeforces.com/contest/1493/problem/C
分析:
此题是一道构造类的思维题目:
思路实际上就是
按照题目的要求,最后要么输出的是-1,要么输出一个字符串,并且如果输出的是一个字符串的话有要求,必须在字典序上大于等于给出的字符串。
所以首先,答案为输出原字符串的情况,很简单,直接算所有的字符是否是k的倍数即可。
输出-1的情况,也简单,字符串长度不是k的整数倍就是输出-1.
最麻烦的就是输出的结果是字典序大于原字符串的情况。
即然大于,那么我们可以从字符串后往前,不断的暴力的去找位置。找到某个位置,将这个位置上的字符,进行枚举(原字符+1 ~ 'z'),而这个位置后面的则可以任意组合。
比如找到了i这个位置是最后答案第一个改变的位置,那么i后面的怎么修改呢?
因为1~i字符不变,只需要统计一下 1 ~ i的所有字符还差多少个字符才能配对成功。
然后进行判断,需要配对的个数 以及 i + 1 ~ n 的个数是否相同,如果可以改变的位置的总个数 >= 需要配对的个数,则满足条件,必定存在一个最优解。
如果改变位置的总个数 > 需要配对的呢?
只要先填充 'a',然后按a ~ z将需要配对的进行配对就可以了。
因为现在第i个一定大于原 第 i 个,所以后面 i + 1 ~ n 可以任意排,都符合题目的大于等于原字符串要求。
# include <iostream>
# include <cstring>
using namespace std;
const int N = 1e5 + 10;
char ch[N];
int num[N][30];
int numtemp[30]; // 用于存num[i]的数据
int t;
int n,k;
int main()
{
scanf("%d",&t);
while(t--)
{
scanf("%d %d",&n,&k);
for(int i = 0 ; i <= n ; i++)
{
for(int j = 0 ; j < 26 ; j++)
{
num[i][j] = 0;
}
}
for(int i = 1 ; i <= n ; i++)
{
cin >> ch[i];
int nums = ch[i] - 'a';
for(int j = 0 ; j < 26 ; j++)
{
num[i][j] = num[i - 1][j];
}
num[i][nums]++;
}
if(n % k)
{
printf("-1\n");
continue;
}
bool flag = true;
for(int i = 0 ; i < 26 ; i++)
{
if(num[n][i] % k != 0)
{
flag = false;
break;
}
}
if(flag)
{
for(int i = 1 ; i <= n ; i++)
{
printf("%c",ch[i]);
}
printf("\n");
continue;
}
for(int i = n ; i >= 1 ; i--) // 从第i个位置到第n - 1个位置可以任意
{
int temp2 = ch[i] - 'a' + 1; // 当前这个位置需要的就是temp2
bool flag2 = false;
for(int tt = temp2 ; tt < 26 ; tt++) // i这个位置进行遍历
{
int pipeinum = 0;
int totalchange = n - i; //除i这个位置外,还能够改变的数量
memcpy(numtemp,num[i - 1],sizeof num[i - 1]);
ch[i] = 'a' + tt; // 这个位置值定下来以后还需要匹配多少个
numtemp[tt] += 1;
for(int j = 0 ; j < 26 ; j++)
{
if(numtemp[j] % k)
{
pipeinum += (numtemp[j] / k + 1) * k - numtemp[j];
}
}
// 还差pipeinum个,
if(pipeinum > totalchange) // 不成立,下一个
{
continue;
}
int yu = totalchange - pipeinum; // 剩下的填a
if(yu % k) // 如果剩余的不能被k整除,不成立
{
continue;
}
int tt2 = i + 1;
for(int j = 1 ; j <= yu ; j++) // 填a
{
ch[tt2++] = 'a';
}
for(int j = 0 ; j < 26 ; j++)
{
while(numtemp[j] % k)
{
ch[tt2++] = 'a' + j;
numtemp[j]++;
}
}
flag2 = true;
break;
}
if(flag2)
{
break;
}
}
for(int i = 1 ; i <= n ; i++)
{
printf("%c",ch[i]);
}
printf("\n");
}
return 0;
}