AT1224 JOIOJI
题面
JOIOJI桑是JOI君的叔叔。“JOIOJI”这个名字是由“J、O、I”三个字母各两个构成的。
最近,JOIOJI桑有了一个孩子。JOIOJI桑想让自己孩子的名字和自己一样由“J、O、I”三个字母构成,并且想让“J、O、I”三个字母的出现次数恰好相同 。
JOIOJI桑家有一份祖传的卷轴,上面写着一首长诗,长度为 \(N\),由“J、O、I”三个字母组成。JOIOJIさん想用诗中最长的满足要求的连续子串作为孩子的名字。
现在JOIOJI桑将这首长诗交给了你,请你求出诗中最长的、包含同样数目的“J、O、I”三个字母的连续子串的长度。
简化题意
有一个由 J
,O
,I
组成的字符串,求一个子串,使得这三个字符出现次数一样。输出子串的长度的最大值。
思路
本题可以用一个前缀和来维护。
令 \(J=1,O=1145141,I=-1145142\),那么就转换成了一个最长的和为 \(0\) 的子串。(之所以取 \(1145141\),是应为这个数比较大)。
枚举 \(i\ (\text{from } 1 \text{ to } n)\)。如果当前子串 \([1,i]\) 的和是 \(0\),那么更新答案。然后就判断存储器中有没有答案,如果有,更新,否则就记录当前和。
至于存储器,可以使用 std::map
实现。
时间复杂度为 \(O(n\log n)\)。
#include <bits/stdc++.h>
#define int long long
using namespace std;
int n;
char poem[200005];
int qzh,result=0;
map<int,int> mem;
signed main(){
cin>>n;
cin>>(poem+1);
for(int i=1;i<=n;i++){
char nch=poem[i];
switch(nch){
case 'J':
qzh++;
break;
case 'O':
qzh+=1145141;
break;
case 'I':
qzh+=(-1145141-1);
break;
}
if(qzh==0){
result=max(result,i);
}
if(mem[qzh]!=0){
result=max(result,i-mem[qzh]);
}
else {
mem[qzh]=i;
}
}
cout<<result<<endl;
return 0;
}