[POI2014]Salad Bar

题目大意:
  一个长度为$n(nleq10^6)$的字符串,每一位只会是$p$或$j$。你需要取出一个子串$S$(从左到右或从右到左一个一个取出),使得不管是从左往右还是从右往左取,都保证每时每刻已取出的$p$的个数不小于$j$的个数。你需要最大化$|S|$。

思路:
  令$p$为$1$,$j$为$-1$。用$sum[i]$表示$1sim i$的前缀和,则题目所求相当于找到一个最长的区间$[l,r]$,满足$forall iin[l,r],sum[l-1]le sum[i]le sum[r]$。
  这也就意味着对于一个满足条件的区间$[l,r]$,$sum[l-1]$为最小值,$sum[r]$为最大值。
  预处理每一个位置$i$能扩展到的最左端点$left[i]$和最右端点$right[i]$。答案相当于找到一个区间$[l,r]$使得$left[r]le l,right[l]ge r$。将点按照$right[i]$排序,枚举对应的$i$作为$l$。用树状数组在每个$left[i]$对应的位置上维护最大的$i$。右端点$r$就是当前加入线段树且$left[i]le l$的点中,对应的$i$的最大值。

 1 #include<cstdio>
 2 #include<cctype>
 3 #include<climits>
 4 #include<algorithm>
 5 inline int getint() {
 6     register char ch;
 7     while(!isdigit(ch=getchar()));
 8     register int x=ch^'0';
 9     while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
10     return x;
11 }
12 inline char getalpha() {
13     register char ch;
14     while(!isalpha(ch=getchar()));
15     return ch;
16 }
17 const int N=1e6+1;
18 int n,a[N],pos[N*2],left[N],right[N],seq[N];
19 inline bool cmp(const int &a,const int &b) {
20     return right[a]<right[b];
21 }
22 class FenwickTree {
23     private:
24         int val[N];
25         int lowbit(const int &x) const {
26             return x&-x;
27         }
28     public:
29         void modify(int p,const int &x) {
30             for(;p<=n;p+=lowbit(p)) {
31                 val[p]=std::max(val[p],x);
32             }
33         }
34         int query(int p) const {
35             int ret=0;
36             for(;p;p-=lowbit(p)) {
37                 ret=std::max(ret,val[p]);
38             }
39             return ret;
40         }
41 };
42 FenwickTree t;
43 int main() {
44     n=getint();
45     for(register int i=1;i<=n;i++) {
46         seq[i]=i;
47         a[i]=getalpha()=='p'?1:-1;
48     }
49     std::fill(&pos[0],&pos[N*2],-1);
50     for(register int i=1,sum=a[1];i<=n;sum+=a[++i]) {
51         left[i]=pos[sum+N+1]+2;
52         pos[sum+N]=i;
53     }
54     std::fill(&pos[0],&pos[N*2],n+2);
55     for(register int i=n,sum=a[n];i>=1;sum+=a[--i]) {
56         right[i]=pos[sum+N+1]-2;
57         pos[sum+N]=i;
58     }
59     int ans=0;
60     std::sort(&seq[1],&seq[n]+1,cmp);
61     for(register int i=1,j=1;i<=n;i++) {
62         const int l=seq[i];
63         if(a[l]==-1) continue;
64         for(;j<=right[l];j++) t.modify(left[j],j);
65         const int r=t.query(l);
66         ans=std::max(ans,r-l+1);
67     }
68     printf("%d
",ans);
69     return 0;
70 }
原文地址:https://www.cnblogs.com/skylee03/p/8651419.html