题意:给定n个正整数,再给出m个正整数k,对于每个k,可以有如下操作:每次选择一个大于k的正整数a[i],将a[i]减去1,选择a[i-1]或a[i+1]中的一个加上1。经过一定次数的操作后,求一个最长的连续子序列满足这个子序列的每个数都不小于k
注意此题判的时候不忽略行末空格_(:3 」∠)_
虽然操作很唬人,但是它最终要求是
一个连续的子序列满足每个数都不小于k 等价于 这个连续的子序列的平均值不小于k
如何维护?
我们把每个数都减去一个k再维护一个前缀和
那么我们满足条件的区间就是 区间[l,r] 满足 sum[r]-sum[l-1]>=0
我们只需要找到r、l即可
显然当 i<j 且 sum[i]<=sum[j] 时选i更优
那么我们对左端点维护一个单调栈
然后从n到1倒序枚举右端点
var
n,m,x :longint;
ans :array[0..55] of longint;
sum :array[0..1000010] of int64;
a,z :array[0..1000010] of longint;
i :longint;
procedure work(x,t:longint);
var
i:longint;
top:longint;
begin
for i:=1 to n do sum[i]:=sum[i-1]+int64(a[i])-int64(x);
top:=1; z[top]:=0;
for i:=1 to n do
if sum[i]<sum[z[top]] then
begin
inc(top);
z[top]:=i;
end;
for i:=n downto 1 do
begin
while (top>0) and (sum[i]-sum[z[top]]>=0) do dec(top);
if i-z[top+1]>ans[t] then ans[t]:=i-z[top+1];
end;
end;
begin
read(n,m);
for i:=1 to n do read(a[i]);
for i:=1 to m do
begin
read(x);
work(x,i);
end;
for i:=1 to m-1 do write(ans[i],' ');writeln(ans[m]);
end.
——by Eirlys