题目:
我是超链接
题解:
f[i][j]=max{f[k][j-1]+(s[n]-s[k])*(s[k]-s[j1])}
每次运行的时候k是已知的
代码:
#include <cstdio>
#include <iostream>
#define LL long long
#define N 100005
using namespace std;
LL f[N],s[N],g[N];int q[N],n;
LL K(int j){return s[j];}
LL B(int j){return -(LL)s[n]*s[j]+g[j];}
LL Y(int i,int j){return (LL)s[i]*K(j)+(LL)B(j);}
bool cover(int x1,int x2,int x3)
{
LL w1=(LL)(K(x1)-K(x2))*(LL)(B(x3)-B(x1));
LL w2=(LL)(K(x1)-K(x3))*(LL)(B(x2)-B(x1));
return w1<=w2;
}
int main()
{
int k,i,x,j;
scanf("%d%d",&n,&k);
for (i=1;i<=n;i++){
scanf("%d",&x);s[i]=s[i-1]+x;
}
LL ans=0;int l,r;
for (i=1;i<=k;i++)
{
l=r=0;
for (j=1;j<=n;j++)
{
while (l<r && Y(j,q[l])<=Y(j,q[l+1])) l++;
f[j]=(LL)Y(j,q[l])+(LL)(s[n]-s[j])*s[j];
while (l<r && cover(j,q[r-1],q[r])) r--;
q[++r]=j;
}
for (j=0;j<=n;j++) g[j]=f[j];
}
for (i=1;i<n;i++) ans=max(ans,g[i]);
printf("%lld",ans);
}
总结:
说一下排除直线的超烦情况吧
y1=k1x+b1 ; y2=k2x+b2 ; y3=k3x+b3
那么现在y1和y3想要把y2挤出去
化简得到的w1=(k1-k2)(b3-b1) ; w2=(k1-k3)(b2-b1)
代表着y1y3的交点的x值对应的y2——y与y2
1、w1**>** w2 ——> y2< y 向上包围取大值
2、w1**<** w2 ——> y2> y 向下包围取小值
恩那就不画图了(才不是懒嘞)