Description
Solution
- 如果a偶数那么b一定不删,末尾为b则删完a,为a则将a花费最小的代价聚在最后。
- 如果a为奇数,最后为a那么用最小代价将a聚集,最后为b则看b是否大于2个,以及前面是否有b来确定是否花费2个b使得开头有b-2个b。
- 注意花费最小代价聚集可以先将所有大小为1的两两消掉。如果用了b-2的操作则看看最后一段a如果有1个是否可以往前面换。
- 总之一点讨论,有点复杂。
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#define maxn 200005
using namespace std;
int T,n,i,j,k,a,b,s[maxn],d[maxn],cnt;
int doit(){
int c0=0,c1=0;
for(i=1;i<d[0];i++) if (d[i]==1) c1++; else c0++;
return a-(c0+c1/2+c1%2)*2;
}
int main(){
freopen("ceshi.in","r",stdin);
freopen("ceshi.out","w",stdout);
scanf("%d",&T); char ch=getchar();
int id=0;
while (T--){
++id;
while (ch!='a'&&ch!='b') ch=getchar();
n=0; while (ch=='a'||ch=='b') s[++n]=ch,ch=getchar();
a=b=0;
for(i=1;i<=n;i++) if (s[i]=='a') a++; else b++;
d[0]=0;
for(i=1;i<=n;i++) if (s[i]=='a'&&(i==1||s[i-1]=='b')){
d[++d[0]]=1;
for(j=i+1;j<=n&&s[j]=='a';j++) d[d[0]]++;
}
if (a&1^1){
while (b--) putchar('b');
if (s[n]=='a'){
cnt=doit();
while (cnt--) putchar('a');
}
} else {
if (s[n]=='a'){
while (b--) putchar('b');
cnt=doit();
while (cnt--) putchar('a');
} else {
k=0;
for(i=n;i>=1&&s[i]=='b';i--) k++;
if (k<=2||b-k==0){
for(i=1;i<=b-k;i++) putchar('b');
putchar('a');
for(i=1;i<=k;i++) putchar('b');
} else {
for(i=1;i<=b-2;i++) putchar('b');
if (d[d[0]]==1){
for(i=1;i<d[0];i++) if (d[i]>1&&(i>1||s[1]=='b')){
swap(d[i],d[d[0]]);
break;
}
}
cnt=doit();
while (cnt--) putchar('a');
}
}
}
putchar('\n');
}
}