【BZOJ4236】JOIOJI STL
【BZOJ4236】JOIOJI
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
JOIIJOJOOI
Sample Output
6
HINT
选择“IIJOJO”这个子串,长度为6,包含“J、O、I”三个字母各2个,这是最长的满足要求的子串。
1<=N<=2*10^5
题解:本题要求三个字符的数量都相同,我们仍然采用前缀相减的方式,设sj,so,si表示J,O,I的前缀出现次数,那么条件就是:
sj[i]-sj[j]=so[i]-so[j]=si[i]-si[j]
移项,得
sj[i]-so[i]=sj[j]-so[j],sj[i]-si[i]=si[i]-si[j]
这样就转变成让i和j的两个权值都相等的问题,用map存一下就好了
然而我一开始忘了map怎么用,手写treap水过~
#include <cstdio> #include <cstring> #include <iostream> #include <cstdlib> using namespace std; const int maxn=200010; int rt[maxn<<1],ch[maxn][2],v[maxn],k[maxn],w[maxn]; int n,tot,s1,s2,s3,ans; char str[maxn]; void rotate(int &x,int d) { int y=ch[x][d]; ch[x][d]=ch[y][d^1]; ch[y][d^1]=x; x=y; } void insert(int &x,int y,int z) { if(!x) { x=++tot; v[x]=y,w[x]=z,k[x]=rand(); return ; } int d=y<v[x]?0:1; insert(ch[x][d],y,z); if(k[ch[x][d]]>k[x]) rotate(x,d); } int find(int x,int y) { if(!x) return 0; if(y==v[x]) return x; if(y<v[x]) return find(ch[x][0],y); return find(ch[x][1],y); } int main() { srand(2333333); scanf("%d",&n); scanf("%s",str); int i; insert(rt[n],0,0); for(i=1;i<=n;i++) { if(str[i-1]=='J') s1++; if(str[i-1]=='O') s2++; if(str[i-1]=='I') s3++; int t=find(rt[s1-s2+n],s2-s3); if(!t) insert(rt[s1-s2+n],s2-s3,i); else ans=max(ans,i-w[t]); } printf("%d",ans); return 0; }
| 欢迎来原网站坐坐! >原文链接<