链接:https://codeforces.com/contest/1530/problem/E
题意:
给出一个字符串,要求对字符重新排序,使得到的新串以从1-1、1-2、1-3、…、1-n的子串中,前后缀相同的长度最大值最小
输出这个串,且需要字典序最小
.
题解:
可以分多种情况考虑
1.每个字母只有一种:从小到大输出
2.只有一种字母:直接输出
3.第一位放两个最小字母:
此种情况的条件是,最小字母的数量少于一半,使得最小字母可以在后面间位排列,也就是说除了首位之外不能出现最小字母
4.第一位放一个最小字母:
当不满足3时,即只能执行4。先放一个最小字母,再放一个次小字母,然后排满最小字母,这时不能在后面继续追加次小字母了,因为这样会使得最长前后缀增加,所以只能再补一个次次小字母,后面按照从小到大的顺序放就可以
注意特殊情况的处理:当只有两种字母时,只能类似于abbbbbbbaaaaaaaa这样排列
#include<bits/stdc++.h>
using namespace std;
int cnt[27];
void solve(){
memset(cnt,0,sizeof cnt);
char fi;
int kind=0;
bool flag=0;
int pos;
char fir;
string tmp;
cin>>tmp;
for(auto i:tmp){//统计字符数与种类
if(cnt[i-'a']==0)kind++;
cnt[i-'a']++;
}
if(kind==1){//只有一种直接输出
cout<<tmp<<endl;
return;
}
for(int i=0;i<26;i++){//定位最小字符的位置
if(cnt[i]){
fi='a'+i;
pos=i+1;
break;
}
}
for(int i=0;i<26;i++){//查找是否有单个字符
if(cnt[i]==1){
flag=1;
fir='a'+i;
break;
}
}
if(flag){//如果有单次出现的字符
cout<<fir;
cnt[fir-'a']--;
for(int i=0;i<26;i++){
if(i!=fir-'a'){
while(cnt[i]){
cout<<char(i+'a');
cnt[i]--;
}
}
}
}else{
if(cnt[fi-'a']-1<=(tmp.length())/2){//如果可以在开头放两个最小字符
cout<<fi<<fi;
cnt[fi-'a']-=2;
for(int i=2;i<tmp.length();i++){
if(i%2==0){
while(cnt[pos]==0)pos++;
cout<<char(pos+'a');
cnt[pos]--;
}else{
if(cnt[fi-'a']>0){
cout<<fi;
cnt[fi-'a']--;
}else{
while(cnt[pos]==0)pos++;
cout<<char(pos+'a');
cnt[pos]--;
}
}
}
}else{//如果只能在开头放一个最小字符
if(kind==2){//只有两种字符时特判
cout<<fi;
cnt[fi-'a']--;
while(cnt[pos]==0)pos++;
while(cnt[pos]>0){
cout<<char(pos+'a');
cnt[pos]--;
}
while(cnt[fi-'a']){
cout<<fi;
cnt[fi-'a']--;
}
}else{//有多于两种字符
cout<<fi;
cnt[fi-'a']--;
while(cnt[pos]==0)pos++;
cout<<char(pos+'a');
cnt[pos]--;
while(cnt[fi-'a']){
cout<<fi;
cnt[fi-'a']--;
}
int tt=pos;
pos++;
while(cnt[pos]==0)pos++;
cout<<char(pos+'a');
cnt[pos]--;
pos=tt;
while(pos<26){
while(cnt[pos]){
cout<<char(pos+'a');
cnt[pos]--;
}
while(cnt[pos]==0)pos++;
}
}
}
}
cout<<endl;
}
int main(){
int t;
cin>>t;
while(t--){
solve();
}
//system("pause");
return 0;
}
一开始只有模糊的想法,没有做出来
看了大佬的博客后,才知道怎么明确的分类
https://www.cnblogs.com/acceptedzhs/p/15028594.html