这题可以用线段树去做,但是比较麻烦。
根据题目可以知道,当一个序列可以成立时,该序列长度必须为偶数且该序列中W的个数要不小于S的个数。
∵总W个数-左W个数-右W个数≥总S个数-左S个数-右S个数
∴总差-左差-右差≥0
∴总差-右差≥左差
右边的差很好求,只要从后往前累加一个前缀和。
为了让结果最大,所以就要尽量往左扩展。
根据上面的公式,设sum[i]表示从左第1位开始累加前缀和小于等于i时最靠左的边界位置。
很显然,一次就可以算出所有的sum[i]。
接着枚举右侧的差,累加一个和,用总和减去右侧的和即为左侧的和。
再套入sum,可以得出最靠左的左边界位置。
但是这种算法没有考虑到一个问题——奇偶性。
比如说,我们当前找到的长度已经大于最大长度,但是由于长度为奇数,所以无法算入答案。
但是有可能此时把左边界向右移一段,虽然长度没有原来那么长,但长度仍然比之前算出的最大长度要大,而且符合条件。
为了考虑到这个问题,在设sum时要分为两种情况来设,计算时也要分别计算。
var
a:array[1..100000,1..2] of longint;
s:array[-100000..100000,0..1] of longint;
sum:array[-100001..100000,0..1] of longint;
n,i,j,k,l,tot,max,r:longint;
ch:char;
procedure swap(var x,y:longint);
var
z:longint;
begin
z:=x;
x:=y;
y:=z;
end;
procedure qsort(l,r:longint);
var
i,j,mid:longint;
begin
i:=l;
j:=r;
mid:=a[(l+r) div 2,1];
while i<=j do
begin
while (a[i,1]<mid) do inc(i);
while (a[j,1]>mid) do dec(j);
if i<=j then
begin
swap(a[i,1],a[j,1]);
swap(a[i,2],a[j,2]);
inc(i);
dec(j);
end;
end;
if l<j then qsort(l,j);
if i<r then qsort(i,r);
end;
begin
assign(Input,'pairphoto.in'); reset(Input);
assign(Output,'pairphoto.out'); rewrite(Output);
readln(n);
for i:=1 to n do
begin
readln(a[i,1],ch,ch);
if ch='W' then
a[i,2]:=1
else
a[i,2]:=-1;
tot:=tot+a[i,2];
end;
qsort(1,n);
for i:=1 to n do
begin
j:=j+a[i,2];
if s[j,i mod 2]=0 then
s[j,i mod 2]:=i;
end;
sum[-n-1,0]:=n*2+1;
sum[-n-1,1]:=n*2+1;
for i:=-n to n do
begin
sum[i]:=sum[i-1];
if (s[i,0]>0) and (sum[i,0]>s[i,0]) then
sum[i,0]:=s[i,0];
if (s[i,1]>0) and (sum[i,1]>s[i,1]) then
sum[i,1]:=s[i,1]; //前缀和
end;
j:=0;
for r:=n downto 1 do
begin
l:=sum[tot-j,0];
if (l<=r) and (a[r,1]-a[l,1]>max) and ((r-l+1) mod 2=0) then
max:=a[r,1]-a[l,1];
l:=sum[tot-j,1];
if (l<=r) and (a[r,1]-a[l,1]>max) and ((r-l+1) mod 2=0) then
max:=a[r,1]-a[l,1];
j:=j+a[r,2]; //分类讨论
end;
writeln(max);
close(Input); close(Output);
end.