BZOJ4384[POI2015] Trzy wieże
Description
給定一個長度爲n的僅包含’B’、’C’、’S’三種字符的字符串,請找到最長的一段連續子串,使得這一段要麼只有一種字符,要麼有多種字符,但是沒有任意兩種字符出現次數相同。
Input
第一行包含一個正整數n(1<=n<=1000000),表示字符串的長度。
第二行一個長度爲n的字符串。
Output
包含一行一個正整數,即最長的滿足條件的子串的長度。
Sample Input
9
CBBSSBCSC
Sample Output
6
HINT
選擇BSSBCS這個子串
Solution:
先分析一下題目的信息,將條件抽象一下:
設
設
於是問題轉化爲找到一個L和R使得
這是一個三維的問題,要想辦法逐漸降維,首先最好考慮的是枚舉順序,我們把
然後我們考慮如何用一個數據結構維護接下來的兩個維度,很顯然可以建一個以
然後我們發現查詢的是前綴與後綴,於是使用樹狀數組就可以完成了。複雜度
還有一點需要注意:別忘了
至於只有一種字符的情況,隨便
#include<stdio.h>
#include<iostream>
#include<algorithm>
#define Max 1000001
#define M 1000005
using namespace std;
char str[M];
int B[M],C[M],sum[3][M],n;
struct Node{
int x,id;
bool operator <(const Node &a)const{
return x<a.x;
}
}A[M];
struct Tree{
int Lmx,Lse,Rmx,Rse;
Tree(){Lmx=Lse=Rmx=Rse=-1;}
}val[2][M<<1];
struct BIT{
int lowbit(int x){return x&(-x);}
void check(Tree &a,int b){
if(a.Lmx==-1)a.Lmx=b;
else{
if(b<a.Lmx){
if(C[a.Lmx]==C[b])a.Lmx=b;
else{
a.Lse=a.Lmx;
a.Lmx=b;
}
}else if((a.Lse==-1)||(b<a.Lse&&C[b]!=C[a.Lmx]))a.Lse=b;
}
if(a.Rmx==-1)a.Rmx=b;
else{
if(b>a.Rmx){
if(C[a.Rmx]==C[b])a.Rmx=b;
else{
a.Rse=a.Rmx;
a.Rmx=b;
}
}else if((a.Rse==-1)||(b>a.Rse&&C[b]!=C[a.Rmx]))a.Rse=b;
}
}
void Add(int x,int a,int p){
while(x<=M*2){
check(val[p][x],a);
x+=lowbit(x);
}
}
int Query(int x,int a,int p){
int mi=n,mx=0;
while(x){
if(val[p][x].Lmx!=-1&&C[val[p][x].Lmx]!=C[a])mi=min(mi,val[p][x].Lmx);
else if(val[p][x].Lse!=-1&&C[val[p][x].Lse]!=C[a])mi=min(mi,val[p][x].Lse);
if(val[p][x].Rmx!=-1&&C[val[p][x].Rmx]!=C[a])mx=max(mx,val[p][x].Rmx);
else if(val[p][x].Rse!=-1&&C[val[p][x].Rse]!=C[a])mx=max(mx,val[p][x].Rse);
x-=lowbit(x);
}
return max(mx-a,a-mi);
}
}BIT;
int main(){
int ans=0;
scanf("%d",&n);
scanf("%s",str+1);
for(int i=1;i<=n;){
int nxt=i;
while(nxt<=n&&str[nxt]==str[i])nxt++;
if(nxt-i>ans)ans=nxt-i;
i=nxt;
}
for(int i=1;i<=n;i++){
sum[0][i]=sum[0][i-1]+(str[i]=='B');
sum[1][i]=sum[1][i-1]+(str[i]=='C');
sum[2][i]=sum[2][i-1]+(str[i]=='S');
A[i].x=sum[0][i]-sum[1][i];
A[i].id=i;
B[i]=sum[1][i]-sum[2][i];
C[i]=sum[0][i]-sum[2][i];
}
A[0].x=0;
A[0].id=0;
sort(A,A+n+1);
for(int i=0;i<=n;){
int now=A[i].x;
int nxt=i;
while(nxt<=n&&A[nxt].x==now)nxt++;
for(int j=i;j<nxt;j++){//Calc
int id=A[j].id;
int res1=BIT.Query(B[id]+Max-1,id,0);
int res2=BIT.Query(Max*2-(B[id]+Max)-1,id,1);
if(res1>ans)ans=res1;
if(res2>ans)ans=res2;
}
for(int j=i;j<nxt;j++){//Add
int id=A[j].id;
BIT.Add(B[id]+Max,id,0);
BIT.Add(Max*2-(B[id]+Max),id,1);
}
i=nxt;
}
printf("%d\n",ans);
return 0;
}