您的位置:首页 > 其它

[BZOJ3675] [Apio2014]序列分割

2015-12-25 12:48 267 查看
dp[i]=max{dp[j]+sum[j]∗(sum[i]−sum[j])}+Cdp[i]=max\{dp[j]+sum[j]*(sum[i]-sum[j])\}+C

dp[i]=max{dp[j]+sum[j]∗sum[i]−sum[j]2}+Cdp[i]=max\{dp[j]+sum[j]*sum[i]-sum[j]^2\}+C

假设j<k且k更优假设j

dp[j]+sum[j]∗sum[i]−sum[j]2<=dp[k]+sum[k]∗sum[i]−sum[k]2dp[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[i]*(sum[k]-sum[j])

(dp[j]−sum[j]2)−(dp[k]−sum[k]2)sum[k]−sum[j]<=sum[i]\frac{(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[i]*(sum[k]-sum[j])

y[j]−y[k]sum[k]−sum[j]<=sum[i]\frac{y[j]-y[k]}{sum[k]-sum[j]}<=sum[i]

dp[i]=min{dp[j]+(sum[i]−sum[j])2}+Cdp[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+Cdp[i]=min\{dp[j]-2*sum[i]sum[j]+sum[j]^2\}+sum[i]^2+C

假设j<k且k更优假设j

dp[j]−2∗sum[i]sum[j]+sum[j]2>=dp[k]−2∗sum[i]sum[k]+sum[k]2dp[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)>=2sum[i]*(sum[j]-sum[k])

(dp[j]+sum[j]2)−(dp[k]+sum[k]2)2∗(sum[j]−sum[k])<=sum[i]\frac{(dp[j]+sum[j]^2)-(dp[k]+sum[k]^2)}{2*(sum[j]-sum[k])}<=sum[i]

ans=sum[n]2−dp[n]ans=sum
^2-dp

传送门

http://www.lydsy.com/JudgeOnline/problem.php?id=3675

题解

作大死~

要来数据本地AC,BZOJ上死活不过

神做法

对于dp[i]=min{dp[j]+(sum[i]−sum[j])2}dp[i]=min\{dp[j]+(sum[i]-sum[j])^2\}我们没办法控制切割段数

所以我们给它加个C

得到dp[i]=min{dp[j]+(sum[i]−sum[j])2}+Cdp[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
>=m
then ll:=mid
else rr:=mid-1;
end;
check(ll);
writeln((s
*s
-dp
+ll*m)>>1);
end.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: