题目
去年暑假在另一个网站DBOJ上也做到了,一点都不会,只能靠暴力骗分水过去
Description
给定一个长度为 n n n 的仅包含 B \texttt B B、 C \texttt C C、 S \texttt S S 三种字符的字符串,请找到最长的一段连续子串,使得这一段要么只有一种字符,要么有多种字符,但是没有任意两种字符出现次数相同。
Solution
以下把B,C,S看作A,B,C
结论一:对于满足条件的最长子段 [ l , r ] [l,r] [l,r],只有两种情况:①3种字母个数都相差1;② l = 1 l=1 l=1或 r = n r=n r=n
证明:假设最优解的
a
<
b
<
c
a<b<c
a<b<c。首先,
c
−
b
c-b
c−b和
b
−
a
b-a
b−a不可能都大于1,。
若①②不成立,则
b
−
a
>
1
b-a>1
b−a>1或
c
−
b
>
1
c-b>1
c−b>1。
不妨设
b
−
a
>
1
b-a>1
b−a>1,则
c
−
b
=
1
c-b=1
c−b=1
因为②不成立,所以右边的位置不能是
a
a
a,
c
c
c,只能是
b
b
b,左边也是这样(不然还能更优)。
此时
a
<
c
<
b
+
2
a<c<b+2
a<c<b+2,能得到更优解,所以原来的不是最优解
结论二:对于子段 [ l , r ] [l,r] [l,r],当 l ∈ [ 1 , 3 ] l∈[1,3] l∈[1,3]或 r ∈ [ n − 2 , n ] r∈[n−2,n] r∈[n−2,n]时一定能找到最优解。
证明:假设最优解
3
<
l
<
=
r
<
n
−
2
3<l<=r<n-2
3<l<=r<n−2。
不妨令此时的
A
,
B
,
C
A,B,C
A,B,C个数分别为
x
,
x
+
1
,
x
+
2
x,x+1,x+2
x,x+1,x+2
左右都扩展三位,假如能证明扩展后一定存在更优方案,我们可以通过不断扩展来保证
l
∈
[
1
,
3
]
l∈[1,3]
l∈[1,3]或
r
∈
[
n
−
2
,
n
]
r∈[n−2,n]
r∈[n−2,n]成立
反证法,假设不存在更优方案,
l
−
1
,
r
+
1
l-1,r+1
l−1,r+1处显然不能有
C
C
C,也不能同时为
B
B
B,那么分类讨论
①
1
A
1
B
1A1B
1A1B,情况变成
A
X
B
AXB
AXB,
A
,
B
,
C
A,B,C
A,B,C总个数分别为
x
+
1
,
x
+
2
,
x
+
2
x+1,x+2,x+2
x+1,x+2,x+2,其中
X
X
X代表扩展前最优解
②
2
A
2A
2A,情况变成
A
X
A
AXA
AXA,
A
,
B
,
C
A,B,C
A,B,C总个数分别为
x
+
2
,
x
+
1
,
x
+
2
x+2,x+1,x+2
x+2,x+1,x+2
对于①,显然两端不能有
B
B
B也不能有
C
C
C(不然有一个就能变
x
+
3
x+3
x+3了),情况变成
A
A
X
B
A
AAXBA
AAXBA
由于
X
B
A
XBA
XBA对应
x
+
1
,
x
+
2
,
x
+
2
x+1,x+2,x+2
x+1,x+2,x+2,所以右侧只能放
A
A
A,
A
A
X
AAX
AAX对应
x
+
2
,
x
+
1
,
x
+
2
x+2,x+1,x+2
x+2,x+1,x+2,所以左侧只能放
B
B
B,情况变成
B
A
A
X
B
A
A
BAAXBAA
BAAXBAA,此时总个数
x
+
4
,
x
+
3
,
x
+
2
x+4,x+3,x+2
x+4,x+3,x+2,还是出现了更优方案,矛盾
对于②,显然两端不能有
A
A
A和
C
C
C,情况变成
B
A
X
A
B
BAXAB
BAXAB
由于
X
A
B
XAB
XAB对应
x
+
1
,
x
+
2
,
x
+
2
x+1,x+2,x+2
x+1,x+2,x+2,所以右侧只能放
A
A
A,左侧
B
A
X
BAX
BAX,情况一样,也只能放
A
A
A,状态变成
A
B
A
X
A
B
A
ABAXABA
ABAXABA,总个数
x
+
4
,
x
+
3
,
x
+
2
x+4,x+3,x+2
x+4,x+3,x+2,更优,矛盾
综上,结论成立
Code
#include<bits/stdc++.h>
using namespace std;
const int N=1000002;
char s1[N];
int i,ans,A,B,C,a[N],b[N],c[N],n,j;
int main(){
scanf("%d%s",&n,s1+1);
for (i=1;i<=n;i++) a[i]=a[i-1]+(s1[i]=='B'),b[i]=b[i-1]+(s1[i]=='C'),c[i]=c[i-1]+(s1[i]=='S');
for (i=1;i<=3;i++)
for (j=n;j-i+1>ans;j--){
A=a[j]-a[i-1];B=b[j]-b[i-1];C=c[j]-c[i-1];
if (A!=B && A!=C && B!=C || (!A)+(!B)+(!C)==2){
ans=j-i+1;
break;
}
}
for (j=n-2;j<=n;j++)
for (i=1;j-i+1>ans;i++){
A=a[j]-a[i-1];B=b[j]-b[i-1];C=c[j]-c[i-1];
if (A!=B && A!=C && B!=C || (!A)+(!B)+(!C)==2){
ans=j-i+1;
break;
}
}
printf("%d",ans);
}