最开始输出98,最开始赶脚是窝姿势不对……偷偷瞄了一眼黄学长的blog感觉get了新姿势,怒码,然后还是98……最后居然是窝括号的位置放错了……过于隐蔽肉眼没能debug出来QAQQQQQQQQQQ……还是太弱了……
这题很显然窝们可以写出Dp方程分程f[i]=f[j]+s[j]*(s[i]-s[j]),因为这题实际上和切的顺序是无关的,其实这很显然证明就是对于答案中的每一个区间必然会被乘上k?次(随便脑补了一下并没有实际计算),然后窝们就可以灰常高兴地写斜率优化啦
当年斜率DP专题比赛怒AK的RP哪去了QAQQQQQQQQQQQ
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 100005
#define LL long long
using namespace std;
LL sum[N],f[N],q[N],a[N],g[N];
int n,k;
LL read()
{
LL x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x;
}
double calc(int j,int k)
{
return (double)(sum[k]*sum[k]-sum[j]*sum[j]-g[k]+g[j])/(double)(sum[k]-sum[j]);
}
void work(int x)
{
int h=1,t=0;
for (int i=x;i<=n;i++)
{
while (h<t&&calc(q[t-1],q[t])>calc(q[t],i-1)) t--;q[++t]=i-1;
while (h<t&&calc(q[h],q[h+1])<sum[i]) h++;int p=q[h];
f[i]=g[p]+(sum[i]-sum[p])*sum[p];
}
for (int i=x;i<=n;i++) swap(f[i],g[i]);
}
void dp()
{
for (int i=1;i<=k;i++)
work(i);
printf("%lld\n",g[n]);
}
int main()
{
n=read();k=read();
for (int i=1;i<=n;i++)
a[i]=read();
int top=0;
for(int i=1;i<=n;i++)
if(a[i]!=0)
a[++top]=a[i];
n=top;
for(int i=1;i<=n;i++)
sum[i]=sum[i-1]+a[i];
dp();
return 0;
}