[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
",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("
");
 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("
");
 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("
");
 47             continue;
 48         }
 49         if (tot%2==0){//Case2
 50             for(int i=0;i<n-tot;i++)printf("b");
 51             printf("
");
 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("
");
 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("
");
 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("
");
 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("
");
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("
");
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("
");
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("
");
132     }
133 }
View Code
原文地址:https://www.cnblogs.com/PYWBKTDA/p/14441254.html