bzoj 4236: JOIOJI 排序&扫描

       首先令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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值