dp[i]=max{dp[j]+sum[j]∗(sum[i]−sum[j])}+C
dp[i]=max{dp[j]+sum[j]∗sum[i]−sum[j]2}+C
假设j<k且k更优
dp[j]+sum[j]∗sum[i]−sum[j]2<=dp[k]+sum[k]∗sum[i]−sum[k]2
(dp[j]−sum[j]2)−(dp[k]−sum[k]2)<=sum[i]∗(sum[k]−sum[j])
(dp[j]−sum[j]2)−(dp[k]−sum[k]2)sum[k]−sum[j]<=sum[i]
y[j]−y[k]<=sum[i]∗(sum[k]−sum[j])
y[j]−y[k]sum[k]−sum[j]<=sum[i]
dp[i]=min{dp[j]+(sum[i]−sum[j])2}+C
dp[i]=min{dp[j]−2∗sum[i]sum[j]+sum[j]2}+sum[i]2+C
假设j<k且k更优
dp[j]−2∗sum[i]sum[j]+sum[j]2>=dp[k]−2∗sum[i]sum[k]+sum[k]2
(dp[j]+sum[j]2)−(dp[k]+sum[k]2)>=2sum[i]∗(sum[j]−sum[k])
(dp[j]+sum[j]2)−(dp[k]+sum[k]2)2∗(sum[j]−sum[k])<=sum[i]
ans=sum[n]2−dp[n]
传送门
http://www.lydsy.com/JudgeOnline/problem.php?id=3675
题解
作大死~
要来数据本地AC,BZOJ上死活不过
神做法
对于
dp[i]=min{dp[j]+(sum[i]−sum[j])2}
我们没办法控制切割段数
所以我们给它加个C
得到
dp[i]=min{dp[j]+(sum[i]−sum[j])2}+C
显然,当C=+∞时,只分为了1段,当C=0时,分为了n段
所以我们二分C,每次判断段数即可
const
maxn=100005;
var
dp,y,s:array[0..maxn]of int64;
t,w,v,ans:array[0..maxn]of longint;
i,j,k,n,m,l,r:longint;
ll,rr,mid:int64;
function check1(a,b,c:longint):boolean;
begin
exit(dp[a]+(s[c]-s[a])*(s[c]-s[a])>=dp[b]+(s[c]-s[b])*(s[c]-s[b]));
end;
function check2(a,b,c:longint):boolean;
var d,e:real;
begin
if (s[b]<>s[a])and(s[c]<>s[b])
then begin
d:=(y[c]-y[b])/(s[c]-s[b]);
e:=(y[b]-y[a])/(s[b]-s[a]);
exit(d<=e); //注意这部分如果都按照else的写法会爆Pascal的int64
end
else exit((y[c]-y[b])*(s[b]-s[a])<=(y[b]-y[a])*(s[c]-s[b]));
end;
procedure check(c:int64);
begin
l:=1;r:=1;t[1]:=0;y[0]:=0;dp[0]:=0;
for i:=1 to n do
begin
while (l<r)and(check1(t[l],t[l+1],i)) do inc(l);
dp[i]:=dp[t[l]]+(s[i]-s[t[l]])*(s[i]-s[t[l]])+c; w[i]:=w[t[l]]+1; y[i]:=dp[i]+s[i]*s[i]; v[i]:=t[l];
while (l<r)and(check2(t[r-1],t[r],i)) do dec(r);
inc(r); t[r]:=i;
end;
end;
begin
readln(n,m); inc(m); s[0]:=0;
for i:=1 to n do
begin read(s[i]); s[i]:=s[i]+s[i-1]; end;
ll:=0;
rr:=maxlongint*300000;
while ll<rr do
begin
mid:=(ll+rr+1)>>1;
check(mid);
if w[n]>=m
then ll:=mid
else rr:=mid-1;
end;
check(ll);
writeln((s[n]*s[n]-dp[n]+ll*m)>>1);
end.