题意:
给定长度为 2 ∗ n 2*n 2∗n的循环字符串,对其重新排列使得新字符串中不存在两个及以上长度为 n n n的相同子串,问能否构造成功并输出任意新字符串。
思路:
首先容易发现新串是否合法与出现最多字符的数量有关,稍微打个表发现:出现次数最多的字符(一下称
c
h
ch
ch)出现了
x
x
x次.
①
①
①如果
x
<
=
n
x <= n
x<=n,那么我们直接输出原串就好了。
②
②
②如果字符种类数
>
=
3
>=3
>=3,那么一定有解(就是间隔构造)
③
③
③如果
x
>
=
2
∗
n
−
2
x >= 2*n-2
x>=2∗n−2,并且字符种类数
=
=
2
==2
==2,那么一定无解
④
④
④如果
x
<
2
∗
n
−
2
x < 2*n-2
x<2∗n−2,并且字符种类数
=
=
2
==2
==2,那么可以先构造出
n
n
n个
c
h
ch
ch,然后插一个其他字符,再扔进剩下的
c
h
ch
ch,再扔进剩下的其他字符,这样就保证了不会出现连续的大于
n
n
n个相同的字符。
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e6+5;
char s[maxn];
set<char>st;
int num[30];
char t1[maxn],t2[maxn];
int main(){
scanf("%s",s+1);
int len = strlen(s+1);
int n = len/2;
for(int i = 1; i <= len; i++){
st.insert(s[i]);
num[s[i]-'a']++;
}
if(st.size() <= 1) puts("NO");
else if(st.size() >= 2){
int mx = 0,val = 0;
for(int i = 0; i < 26; i++){
if(num[i]) val++;
mx = max(mx, num[i]);
}
int cnt1 = 0, cnt2 = 0;
for(int i = 0; i < 26; i++){
if(num[i] == 0) continue;
if(num[i] == mx) for(int j = 0; j < num[i]; j++) t1[cnt1++] = i+'a';
else for(int j = 0; j < num[i]; j++) t2[cnt2++] = i+'a';
}
if(st.size() == 2){
if(mx <= n){
puts("YES");
sort(s+1,s+len+1);
puts(s+1);
}
else if(mx >= 2*n-2) puts("NO");
else{
puts("YES");
int c1 = 0, c2 = 0;
for(int i = 0; i < min(n, mx); i++) printf("%c",t1[i]);
c1 = min(n,mx);
if(cnt2){
printf("%c",t2[0]);
c2 = 1;
}
for(int i = c1; i < cnt1; i++) printf("%c",t1[i]);
for(int i = c2; i < cnt2; i++) printf("%c",t2[i]);
}
}else{
puts("YES");
int c1 = 0, c2 = 0;
for(int i = 0; i < min(n, mx); i++) printf("%c",t1[i]);
c1 = min(n,mx);
if(cnt2){
printf("%c",t2[0]);
c2 = 1;
}
for(int i = c1; i < cnt1; i++) printf("%c",t1[i]);
for(int i = c2; i < cnt2; i++) printf("%c",t2[i]);
}
}
}