BZOJ 4236 "JOIOJI"(前缀和+map+pair)

传送门:

  [1]:BZOJ

  [2]:洛谷

 

•题解

  定义数组 a,b,c 分别表示 'J' , 'O' , 'I' 的前缀和;

  要想使区间 (L,R] 满足条件当且仅当 a[R]-a[L] = b[R]-b[L] = c[R]-c[L];

  那么,由 a[R]-a[L] = b[R]-b[L] ⇔ a[R]-b[R] = a[L]-b[L];

  同理,由 b[R]-b[L] = c[R]-c[L] ⇔ b[R]-c[R] = b[L]-c[L];

  提前预处理出 a,b,c 数组后;

  对于 i 位置,查找之前是否含有满足 ai-bi = aj-bj && bi-ci = bj-cj 的位置 j,并且 j 尽可能的小;

  如何高效的查找呢?

  使用 map<pair<int ,int > , int >;

  对于之前处理过的位置 j ,将 aj-bj 和 bj-cj 存入到 pair<int ,int > 中,每次查找是否存在 (ai-bi,bi-ci) 即可;

  如果存在,求解当前答案,反之,将其加入到map中;

•Code

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define pii pair<int ,int >
 4 const int maxn=2e5+50;
 5 
 6 int n;
 7 char s[maxn];
 8 int a[maxn];
 9 int b[maxn];
10 int c[maxn];
11 map<pii ,int >f;
12 
13 int Solve()
14 {
15     f.clear();
16     f[pii(0,0)]=0;///将(0,0)加入到f中
17     a[0]=b[0]=c[0]=0;
18 
19     int len=strlen(s+1);
20     for(int i=1;i <= len;++i)
21     {
22         a[i]=a[i-1]+(s[i] == 'J');
23         b[i]=b[i-1]+(s[i] == 'O');
24         c[i]=c[i-1]+(s[i] == 'I');
25     }
26 
27     int ans=0;
28     for(int i=1;i <= len;++i)
29     {
30         pii tmp=pii(a[i]-b[i],b[i]-c[i]);
31         if(f.count(tmp))
32             ans=max(ans,i-f[tmp]);
33         else
34             f[tmp]=i;
35     }
36     return ans;
37 }
38 int main()
39 {
40     scanf("%d",&n);
41     scanf("%s",s+1);
42 
43     printf("%d\n",Solve());
44 
45     return 0;
46 }
View Code

 

posted @ 2019-07-22 19:41  HHHyacinth  阅读(215)  评论(0编辑  收藏  举报