题解 P4756 【Added Sequence】
考虑最大的
换为前缀和的形式
将绝对值拆掉
所以
如果给整个数组加上
那么当我们确定了整个数组加上的数字
这个是个一次函数的形式,我们可以将前面的
这个是样例的图,其中紫色的为5条一次函数,黄色的为下凸包,红色的为下凸包。那么当我们要求整个数组加上
那么我们维护凸包,记下凸包上每条线段两端的位置后,我们可以二分横坐标
最后上凸包的值-下凸包的值即为答案。
时间复杂度为
#include <bits/stdc++.h>
#define MN 200005
#define ll long long
using namespace std;
int n,m,l,r,mid,a,b,x;
ll s[MN],mx[MN],mxn,mn[MN],mnn,pre;
double mxp[MN],mnp[MN];
inline int read()
{
int x=0,f=1;char c;
while((c=getchar())<'0'||c>'9')if(c=='-')f=-1;
for(;c>='0'&&c<='9';c=getchar())x=x*10+c-'0';
return x*f;
}
inline double cal(int a,int b){return double(s[b]-s[a])/(a-b);}
int main()
{
n=read();m=read();
for(int i=1;i<=n;i++)
{
s[i]=s[i-1]+read();
while(mxn&&cal(i,mx[mxn])<=cal(i,mx[mxn-1]))--mxn;mx[++mxn]=i;
while(mnn&&cal(i,mn[mnn])>=cal(i,mn[mnn-1]))--mnn;mn[++mnn]=i;
}
for(int i=1;i<=mxn;i++)mxp[i]=cal(mx[i],mx[i-1]);
for(int i=1;i<=mnn;i++)mnp[i]=cal(mn[i],mn[i-1]);
while(m--)
{
x=(read()+pre)%(4*n+1)-2*n;
if(x<=mxp[1])a=0;
else for(l=1,r=mxn;l<=r;)
{
mid=(l+r)>>1;
if(x>=mxp[mid])a=mx[mid],l=mid+1;
else r=mid-1;
}
if(x>=mnp[1])b=0;
else for(l=1,r=mnn;l<=r;)
{
mid=(l+r)>>1;
if(x<=mnp[mid])b=mn[mid],l=mid+1;
else r=mid-1;
}
printf("%lld\n",pre=(ll)(a-b)*x+s[a]-s[b]);
}
return 0;
}