4236: JOIOJI
Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 1160 Solved: 502
[ Submit][ Status][ Discuss]
Description
JOIOJI桑是JOI君的叔叔。“JOIOJI”这个名字是由“J、O、I”三个字母各两个构成的。
最近,JOIOJI桑有了一个孩子。JOIOJI桑想让自己孩子的名字和自己一样由“J、O、I”三个字母构成,并且想让“J、O、I”三个字母的出现次数恰好相同。
JOIOJI桑家有一份祖传的卷轴,上面写着一首长诗,长度为N,由“J、O、I”三个字母组成。JOIOJIさん想用诗中最长的满足要求的连续子串作为孩子的名字。
现在JOIOJI桑将这首长诗交给了你,请你求出诗中最长的、包含同样数目的“J、O、I”三个字母的连续子串。
Input
第一行一个正整数N,代表这首长诗的长度
接下来一行一个长度为N的字符串S,表示这首长诗,保证每个字符都是“J、O、I”三个字母中的一个
Output
输出一行一个正整数,代表最长的包含等数量“J、O、I”三个字母的最长连续子串的长度。如果不存在这样的子串,输出0
Sample Input
10
JOIIJOJOOI
Sample Output
6
令dp[i][0]表示前i个字符中'J'出现的次数
dp[i][1]表示前i个字符中'O'出现的次数
dp[i][2]表示前i个字符中'I'出现的次数
那么子串[b, e]满足三个单词出现次数相等的充要条件就为
dp[e][1]-dp[e][0]==dp[b][1]-dp[b][0]
dp[e][2]-dp[e][1]==dp[b][2]-dp[b][1]
所以只要开个map存这两个差值第一次出现的位置(用pair存)就好了,遍历时对于当前位置,找到第一次这两个差值都相同的地方,中间的串就满足条件,求最长的这个长度
#include<stdio.h>
#include<map>
#include<algorithm>
using namespace std;
map<pair<int, int>, int> p;
char str[200005];
int dp[200005][3];
int main(void)
{
int n, i, ans;
while(scanf("%d%s", &n, str+1)!=EOF)
{
ans = 0;
p.clear();
p[make_pair(0,0)] = 0;
for(i=1;i<=n;i++)
{
dp[i][0] = dp[i-1][0]+(str[i]=='J');
dp[i][1] = dp[i-1][1]+(str[i]=='O');
dp[i][2] = dp[i-1][2]+(str[i]=='I');
if(p.count(make_pair(dp[i][0]-dp[i][1], dp[i][1]-dp[i][2]))==0)
p[make_pair(dp[i][0]-dp[i][1], dp[i][1]-dp[i][2])] = i;
ans = max(ans, i-p[make_pair(dp[i][0]-dp[i][1], dp[i][1]-dp[i][2])]);
}
printf("%d\n", ans);
}
return 0;
}