正题
首先可以列出一条式子,无论是把他放在前面还是后面,都满足:若x放在y前面,就有代价=
这个可以自己验算一下,在做题的时候我直接把这个东西拆开来,就变成了一个类似整体减去一个值,再求最大后缀的问题,那个问题是不能poly log解决的,很麻烦。
结果看了题解,发现这个很简单,因为观察上面的式子,可以发现不能确定的只有,那么这个东西若令
,就是一个斜率的形式,产生贡献的点就在凸包上面了,由于
不是单调的,于是可以三分了。
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
using namespace std;
const int N=200010;
int n,a[N];
long long sum[N];
struct node{
long long x,y;
}sta[N];
int top=0;
void read(int&x){
char ch=getchar();x=0;
int f=1;
while(ch<'0' || ch>'9') {if(ch=='-') f=-1;ch=getchar();}
while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
x*=f;
}
long long get_x(node a,node b,node c){
long long x1=b.x-a.x,y1=b.y-a.y,x2=c.x-a.x,y2=c.y-a.y;
return x1*y2-x2*y1;
}
long long get_value(int x,int y){
if(y==0) return 0;
return sum[x-1]-1ll*a[x]*x+sta[y].y+a[x]*sta[y].x;
}
long long get_max(int x){
int l=1,r=top;
int ans=0;
while(l<r){
int op=r-l,mid1=l+op/3,mid2=l+op*2/3;
long long v1=get_value(x,mid1),v2=get_value(x,mid2);
if(v1<v2) l=mid1+1;
else if(v1>v2) r=mid2-1;
else ans=mid1,l=mid1+1,r=mid2-1;
}
return max(get_value(x,ans),get_value(x,l));
}
int main(){
long long tot=0;
read(n);
for(int i=1;i<=n;i++) read(a[i]),sum[i]=sum[i-1]+a[i],tot+=1ll*i*a[i];
sta[++top]=(node){1,-sum[0]};
sta[++top]=(node){2,-sum[1]};
for(int i=3;i<=n+1;i++){
node X=(node){i,-sum[i-1]};
while(top>=2 && get_x(sta[top-1],sta[top],X)>=0) top--;
sta[++top]=X;
}
long long ans=0;
for(int i=1;i<=n;i++)
ans=max(ans,get_max(i));
printf("%lld",tot+ans);
}
本文探讨了一种利用三分法求解最优代价的算法问题。通过观察特定式子,将其转化为斜率形式,并利用三分法在凸包上寻找产生最大贡献的点。代码示例展示了如何实现这一算法,包括读取输入、计算累积和、维护凸包以及最终求解最优解的过程。
237

被折叠的 条评论
为什么被折叠?



