[atARC112E]Rvom and Rsrev
毒瘤分类讨论题
(注:以下情况都有“之前的情况都不满足的”前提条件,并用斜体表示一些说明)
Case0:若$|s|\le 2$,直接输出即可,因此假设$|s|>3$
首先,我们最希望在不对$b$操作的前提下(不减小$b$的数量)使得所有$b$都在最前面,此时即最大化后缀$a$的数量,由于每一次操作减少两个$a$,即最小化操作数
Case1:以$a$为结尾(不难证明此时总是可以达到我们最希望的情况)
Case1.1:以$aa$为结尾,将$a$通过$b$划分为若干个非空段,根据长度分为两类:
1.对于非结尾且长度大于1的段,将该段第一个$a$与结尾段的第一个$a$操作,每一段多1次操作
2.对于(非结尾且)长度为1的段,与同类的段相互抵消,需要段数除以2上取整次操作
Case1.2:以$ba$为结尾,同样将其划分后,再分类讨论
Case1.2.1:若不存在长度大于2的段,则永远无法使得最终结尾$a$的个数大于1,因此最终个数取决于初始$a$个数的奇偶性(即0或1)
Case1.2.2:无特殊限制(存在长度大于2的段),将该段第一个$a$与结尾的$a$操作后,即与Case1.1相同
事实上,由于恰好不考虑最后一段$a$以及每一段$a$都要一次操作,所以与Case1.1完全相同
Case2:$a$的个数为偶数,此时直接成对来删除所有$a$即可
如果不满足Case1和Case2,那么是达不到最希望的情况的,此时根据是否对$b$操作来分类
对$b$操作的基本思路是将末尾的$b$与一个$a$之前的$b$操作使得以$a$为结尾,那么至少要损失两个$b$,同时能够做到让剩下的$b$都在最前面
Case3:整个字符串中不存在形如$ba$的形式,或以$abb$、$ab$结尾
此时选择不对$b$操作,显然保留最后的$a$,将其余$a$成对消除即可
Case4:无特殊条件(不满足Case1、Case2和Case3)
Case4.1:不以$a$为开头
注意到与长度大于1的段之前的$b$操作一定会使得答案减小2,而与长度为1的段之前的$b$操作至多使答案减小2,因此显然与长度大于1的段之前的$b$操作
Case4.1.1:不存在长度大于1的段,那么与Case1.2.1相同,最终结尾的$a$个数即初始$a$个数奇偶性
Case4.1.2:存在长度大于1的段,将末尾的$b$与该段开头的$b$操作后与Case1.1相同
Case4.2:以$a$为开头
Case4.2.1:以$ab$为开头或存在不在开头且长度大于1的段,此时与Case4.1同样操作即可
Case4.2.2:无特殊限制(以$aa$为开头且不存在不在开头且长度大于1的段),此时先将末尾的$b$与任意一个$a$之前的$b$(长度都是1)操作,之后与Case1.2相同
先将开头的$a$与某一个$a$操作是等价的,此时对应于Case4.1
1 #include<bits/stdc++.h> 2 using namespace std; 3 int t; 4 char s[200005]; 5 int main(){ 6 scanf("%d",&t); 7 while (t--){ 8 scanf("%s",s); 9 int n=strlen(s),tot=0; 10 if (n<=2){//Case0 11 printf("%s\n",s); 12 continue; 13 } 14 for(int i=0;i<n;i++) 15 if (s[i]=='a')tot++; 16 if (s[n-1]=='a'){//Case1 17 for(int i=0;i<n-tot;i++)printf("b"); 18 int one=0,sum=0; 19 if (s[n-2]=='a'){//Case1.1 20 for(int i=0;i<n;i++) 21 if ((s[i]=='a')&&(i<n-1)&&(s[i+1]=='b')){ 22 if ((!i)||(s[i-1]=='b'))one++; 23 else sum++; 24 } 25 sum+=(one+1)/2; 26 for(int i=0;i<tot-2*sum;i++)printf("a"); 27 printf("\n"); 28 continue; 29 } 30 //Case1.2 31 bool flag=0; 32 for(int i=0;i<n-2;i++) 33 if ((s[i]=='a')&&(s[i+1]=='a')&&(s[i+2]=='a'))flag=1; 34 if (!flag){//Case1.2.1 35 if (tot&1)printf("a"); 36 printf("\n"); 37 continue; 38 } 39 for(int i=0;i<n;i++) 40 if ((s[i]=='a')&&(i<n-1)&&(s[i+1]=='b')){ 41 if ((!i)||(s[i-1]=='b'))one++; 42 else sum++; 43 } 44 sum+=(one+1)/2; 45 for(int i=0;i<tot-2*sum;i++)printf("a"); 46 printf("\n"); 47 continue; 48 } 49 if (tot%2==0){//Case2 50 for(int i=0;i<n-tot;i++)printf("b"); 51 printf("\n"); 52 continue; 53 } 54 int flag=0,las=-1; 55 for(int i=1;i<n;i++) 56 if ((s[i-1]=='b')&&(s[i]=='a'))flag=1; 57 for(int i=0;i<n;i++) 58 if (s[i]=='a')las=i; 59 if ((!flag)||(las>=n-3)){//Case3 60 for(int i=0;i<las;i++) 61 if (s[i]=='b')printf("b"); 62 printf("a"); 63 for(int i=las+1;i<n;i++) 64 if (s[i]=='b')printf("b"); 65 printf("\n"); 66 continue; 67 } 68 //Case4 69 for(int i=0;i<n-tot-2;i++)printf("b"); 70 if (s[0]!='a'){//Case4.1 71 bool flag=0; 72 for(int i=0;i<n-1;i++) 73 if ((s[i]=='a')&&(s[i+1]=='a'))flag=1; 74 if (!flag){//Case4.1.1 75 if (tot&1)printf("a"); 76 printf("\n"); 77 continue; 78 } 79 //Case4.1.2 80 int one=0,sum=-1; 81 for(int i=0;i<n;i++) 82 if ((s[i]=='a')&&(i<n-1)&&(s[i+1]=='b')){ 83 if ((!i)||(s[i-1]=='b'))one++; 84 else sum++; 85 } 86 sum+=(one+1)/2; 87 for(int i=0;i<tot-2*sum;i++)printf("a"); 88 printf("\n"); 89 continue; 90 } 91 //Case4.2 92 flag=0; 93 for(int i=0;i<n-1;i++){ 94 if ((s[i]=='b')&&(!flag))flag=1; 95 if ((flag)&&(s[i]=='a')&&(s[i+1]=='a'))flag=2; 96 } 97 if ((s[1]=='b')||(flag>1)){//Case4.2.1 98 bool flag=0; 99 for(int i=0;i<n-1;i++) 100 if ((s[i]=='a')&&(s[i+1]=='a'))flag=1; 101 if (!flag){ 102 if (tot&1)printf("a"); 103 printf("\n"); 104 continue; 105 } 106 int one=0,sum=-1; 107 for(int i=0;i<n;i++) 108 if ((s[i]=='a')&&(i<n-1)&&(s[i+1]=='b')){ 109 if ((!i)||(s[i-1]=='b'))one++; 110 else sum++; 111 } 112 sum+=(one+1)/2; 113 for(int i=0;i<tot-2*sum;i++)printf("a"); 114 printf("\n"); 115 continue; 116 } 117 //Case4.2.2 118 if ((s[0]!='a')||(s[1]!='a')||(s[2]!='a')){ 119 if (tot&1)printf("a"); 120 printf("\n"); 121 continue; 122 } 123 int one=-1,sum=0; 124 for(int i=0;i<n;i++) 125 if ((s[i]=='a')&&(i<n-1)&&(s[i+1]=='b')){ 126 if ((!i)||(s[i-1]=='b'))one++; 127 else sum++; 128 } 129 sum+=(one+1)/2; 130 for(int i=0;i<tot-2*sum;i++)printf("a"); 131 printf("\n"); 132 } 133 }