P4983 忘情
这题真的很裸吧,就是一个更为简单的\(\text{wqs}\)二分然后斜率优化。
题目里的式子稍加推导发现就是\((sum+1)^2\),斜率优化即可。
注意这里斜率比较不能用乘法,因为会爆\(\text{long long}\),然后二分的边界要开大一点。
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxn=2e5+10;
const int mod=1e9+7;
int n,m,a[maxn],sum[maxn],f[maxn],num[maxn],q[maxn];
inline int read(){
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
return x*f;
}
inline int yval(int x){return f[x]+sum[x]*sum[x]-2*sum[x];}
inline int dx(int x,int y){return sum[y]-sum[x];}
inline int dy(int x,int y){return yval(y)-yval(x);}
inline double slope(int x,int y){return 1.0*dy(x,y)/dx(x,y);}
inline void calc(int val){
int l,r;q[l=r=1]=0;
for(int i=1;i<=n;i++){
while(l<r&&slope(q[l],q[l+1])<=2*sum[i])l++;
f[i]=f[q[l]]+(sum[i]-sum[q[l]]+1)*(sum[i]-sum[q[l]]+1)+val;
num[i]=num[q[l]]+1;
while(l<r&&slope(q[r],i)<=slope(q[r-1],q[r]))r--;
q[++r]=i;
}
}
signed main(){
n=read(),m=read();
for(int i=1;i<=n;i++)a[i]=read();
for(int i=1;i<=n;i++)sum[i]=sum[i-1]+a[i];
int l=0,r=1e18;
for(int i=1;i<=100;i++){
int mid=(l+r)>>1;
calc(mid);
if(num[n]>m)l=mid;
else r=mid;
}
calc(l);
printf("%lld\n",f[n]-l*m);
return 0;
}