bzoj4236 JOIOJI

题目大意:从一个只有J、O、I的子串截取一个最长的子串,要求子传中J、O、I的数量相等;
题解:
自己并不会做 ,题单里标签是神题,看完题解后我也有同感。
定义s0,s1,s2是JOI三个字母个数的前缀和,那么对于i,j+1两个位置之间的子串如果满足要求,那么一定有:s0i-s0j=s1i-s1j=s2i-s2j;
等式同时减掉s0i-s0j,那么:s1i-s1j-s0i+s0j=s2i-s2j-s0i+s0j=0;
即是:s1i-s0i=s1j-s0j;s2i-s0i=s2j-s0j;
即满足以上条件,这段长度为j-i的字符串有解;
所以记录每一个点的s1j-s0j,s2j-s0j;在每一个新位置计算新位置的差,如果满足条件,那么这段字符串一定有解。可以用map维护这些点。
P.S.我在程序里用的是0-1,1-2,和题解中的1-0,2-0同理。
P.S.自己写的读入炸了,全部wa掉,从网上抄了一份,以后要注意这种读入的写法。

#include<bits/stdc++.h>
using namespace std;
map<pair<int,int>,int>m;
const int maxn=2*1e5+10;
int n,a[maxn],sum[3];
void read()
{
    scanf("%d",&n); char op;
    for(int i=1;i<=n;i++)
    {
        op=getchar(); while(op!='J'&&op!='O'&&op!='I')op=getchar();
        a[i]=op=='J'?0:(op=='O'?1:2); 
    }
    return ;
}
/*inline void read()
{
	char c=getchar();int cnt=0;
	while(c!='J'&&c!='O'&&c!='I')	c=getchar();
	while(c=='J'||c=='O'||c=='I'){
		int flag;if(c=='J')	flag=0;
		else if(c=='O')	flag=1;else flag=2;
		cnt++,a[cnt]=flag;c=getchar();
	}
}*/
int main()
{
	int ans=0;
	//scanf("%d",&n);
	read();
	pair<int,int>t;t=make_pair(0,0);
	m[t]=0;
	for(int i=1;i<=n;i++){
		sum[a[i]]++;
		t=make_pair(sum[0]-sum[1],sum[1]-sum[2]);
		if(m.find(t)==m.end())
			m[t]=i;
		else
			ans=max(ans,i-m[t]);
	}
	printf("%d\n",ans);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值