您的位置:首页 > 其它

BZOJ3521: [Poi2014]Salad Bar

2016-05-11 19:08 441 查看
题目大意:有一个长度为n的字符串,每一位只会是p或j。求一个最长子串,使得不管是从左往右还是从右往左取,都保证每时每刻已取出的p的个数不小于j的个数。

首先先扫一遍得到以每个点为左端点,只考虑从左向右取,最远能取到哪,并标记每一个点最早被哪一个点扫到

然后再从后往前扫一遍,开两个栈,一个记录当前仍符合条件的右端点,一个记录已经被扫过的左端点,每当有元素从第一个栈里弹出时,就在第二个栈里二分找出符合两个条件的最远的左端点

#include<iostream>
#include<cstdio>
#define N 1000010
using namespace std;
char c
;
int pre
;
int s
,t;
int fir
,far
;
int b
,p;
int main()
{
int n;
scanf("%d",&n);
int i,j;
scanf("%s",c+1);
for(i=1;i<=n;i++)
{
if(c[i]=='p')
pre[i]=pre[i-1]+1;
else pre[i]=pre[i-1]-1;
}
for(i=1;i<=n;i++)
{
while(t&&pre[i]-pre[s[t]-1]<0)
{
far[s[t]]=i-1;
t--;
}
if(t) fir[i]=s[1];
else if(pre[i]-pre[i-1]==1) fir[i]=i;
else fir[i]=707185547;
if(pre[i]-pre[i-1]==1) t++,s[t]=i;
}
while(t)
{
far[s[t]]=n;
t--;
}
int ans=0;
int L,R,mid;
for(i=n;i>=1;i--)
{
while(t&&pre[s[t]]-pre[i-1]<0)
{
L=2;R=p+1;
while(L<R)
{
mid=(L+R)>>1;
if(far[b[mid]]>=s[t]) L=mid+1;
else R=mid;
}
ans=max(ans,s[t]-max(fir[s[t]]-1,b[L-1]-1));
t--;
}
if(pre[i]-pre[i-1]==1)
{
t++;s[t]=i;
while(p&&far[b[p]]<=far[i]) p--;
p++;b[p]=i;
}
}
while(t)
{
L=2;R=p+1;
while(L<R)
{
mid=(L+R)>>1;
if(far[b[mid]]>=s[t]) L=mid+1;
else R=mid;
}
ans=max(ans,s[t]-max(fir[s[t]]-1,b[L-1]-1));
t--;
}
printf("%d",ans);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: