首先令sJ[i],sO[i],sI[i]分别表示1~i位中'J','O','I'的个数,那么某一个子串i~j中'J','O','I'的个数相同的条件为:
sJ[j]-sJ[i-1]=sO[j]-sO[i-1]=sI[j]-sI[i-1]
然后上式等号三边(。。理解就好>_<)减去sJ[j]-sJ[i-1],得到:
0=sO[j]-sJ[j]-(sO[i-1]-sJ[i-1])=sI[j]-sJ[j]-(sI[i-1]-sJ[i-1]),那么如果令x[i]=sO[i]-sJ[i],y[i]=sI[i]-sJ[i],那么就变成
x[i-1]=x[j]且y[i-1]=y[j]
那么令一个点i为(x[i],y[i]),点权为i,那么就相当于查询最大的相同位置点券差。快排一下扫一遍即可。
AC代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n; struct node{ int x,y,id; }a[200005];
bool cmp(node u,node v){
return u.x<v.x || u.x==v.x && u.y<v.y || u.x==v.x && u.y==v.y && u.id<v.id;
}
int main(){
scanf("%d",&n); int i; char ch=getchar();
while (ch<'A' || ch>'Z') ch=getchar();
for (i=1; i<=n; i++){
if (ch=='J'){ a[i].x=a[i-1].x-1; a[i].y=a[i-1].y-1; }
else if (ch=='O'){ a[i].x=a[i-1].x+1; a[i].y=a[i-1].y; }
else{ a[i].x=a[i-1].x; a[i].y=a[i-1].y+1; }
a[i].id=i; if (i<n) ch=getchar();
}
sort(a,a+n+1,cmp);
int now=a[0].id,ans=0;
for (i=1; i<=n; i++)
if (a[i].x==a[i-1].x && a[i].y==a[i-1].y) ans=max(ans,a[i].id-now);
else now=a[i].id;
printf("%d\n",ans);
return 0;
}
by lych
2016.3.18