【BZOJ4236】JOIOJI [DP]
JOIOJI
Time Limit: 10 Sec Memory Limit: 256 MB[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
HINT
选择“IIJOJO”这个子串,长度为6,包含“J、O、I”三个字母各2个,这是最长的满足要求的子串。
1<=N<=2*10^5
Solution
假装这是个DP吧qwq。
Code
1 #include<iostream>
2 #include<string>
3 #include<algorithm>
4 #include<cstdio>
5 #include<cstring>
6 #include<cstdlib>
7 #include<cmath>
8 #include<map>
9 using namespace std;
10 typedef long long s64;
11
12 const int ONE = 2e5+5;
13
14 map <pair<int, int>, int> Map;
15 int n;
16 char S[ONE];
17 int f[ONE][4];
18 int Ans;
19
20 int get()
21 {
22 int res=1,Q=1;char c;
23 while( (c=getchar())<48 || c>57 )
24 if(c=='-')Q=-1;
25 res=c-48;
26 while( (c=getchar())>=48 && c<=57 )
27 res=res*10+c-48;
28 return res*Q;
29 }
30
31 int id(char S) {return S=='J' ? 1:(S=='O' ? 2 : 3);}
32 int main()
33 {
34 n = get();
35 scanf("%s", S+1);
36 Map[make_pair(0,0)] = 0;
37 for(int i=1; i<=n; i++)
38 {
39 memcpy(f[i], f[i-1], sizeof(f[i-1]));
40 f[i][id(S[i])]++;
41
42 pair<int,int> t = make_pair(f[i][1] - f[i][2], f[i][2] - f[i][3]);
43 if(Map.find(t) == Map.end()) Map[t] = i;
44 else Ans = max(Ans, i - Map[t]);
45 }
46 printf("%d", Ans);
47 }