传送门
SOL
tips:
方差:
方程:
f
[
m
]
[
n
]
f[m][n]
f[m][n]:第m天在n点的 方差*m^2 的最小值
P
[
m
]
[
n
]
P[m][n]
P[m][n]第m天在n点的 分成 m份的 平方和的 最小值
(
a
1
2
+
a
2
2
+
.
.
.
+
a
n
2
a_1^2+a_2^2+...+a_n^2
a12+a22+...+an2)
f 有:
f
[
d
]
[
i
]
=
d
∗
P
[
d
−
1
]
[
j
]
+
d
∗
(
s
u
m
[
i
]
−
s
u
m
[
j
]
)
2
−
s
u
m
[
i
]
2
f[d][i]=d*P[d-1][j]+d*(sum[i]-sum[j])^2-sum[i]^2
f[d][i]=d∗P[d−1][j]+d∗(sum[i]−sum[j])2−sum[i]2
变形:
2
∗
d
∗
s
u
m
[
i
]
∗
s
u
m
[
j
]
+
f
[
d
]
[
i
]
−
.
.
.
=
d
∗
(
s
u
m
[
j
]
2
+
P
[
d
−
1
]
[
j
]
)
2*d*sum[i] * sum[j] + f[d][i] -... =d*(sum[j]^2+P[d-1][j])
2∗d∗sum[i]∗sum[j]+f[d][i]−...=d∗(sum[j]2+P[d−1][j])
同时除以d
2 ∗ s u m [ i ] ∗ s u m [ j ] + f [ d ] [ i ] / d − . . . = s u m [ j ] 2 + P [ d − 1 ] [ j ] 2*sum[i]*sum[j]+f[d][i]/d-...=sum[j]^2+P[d-1][j] 2∗sum[i]∗sum[j]+f[d][i]/d−...=sum[j]2+P[d−1][j]
···············································································································································
P有:
P
[
d
]
[
i
]
=
(
s
u
m
[
i
]
−
s
u
m
[
j
]
)
2
+
P
[
d
−
1
]
[
j
]
P[d][i]= (sum[i]-sum[j])^2+ P[d-1][j]
P[d][i]=(sum[i]−sum[j])2+P[d−1][j]
变形:
2
∗
s
u
m
[
i
]
∗
s
u
m
[
j
]
+
P
[
d
]
[
i
]
−
.
.
.
=
P
[
d
−
1
]
[
j
]
+
s
u
m
[
j
]
2
2*sum[i] * sum[j] + P[d][i] -... = P[d-1][j]+sum[j]^2
2∗sum[i]∗sum[j]+P[d][i]−...=P[d−1][j]+sum[j]2
发现计算 (P) 和 (f)的斜率式子的 x , y , k都是相同的,
所以 P的最优决策点就是 f 的 最优决策点,
处理完P之后直接用停在 head 的 点 求就可以了
CODE
#include<bits/stdc++.h>
using namespace std;
#define sf scanf
#define pf printf
#define ll long long
#define db double
const int N=3e3+5;
ll P[N][N];
int sum[N],q[N],head,tail,n,m;
/*
f[d][i]=d*P[d-1][j]+d*(sum[i]-sum[j])^2-sum[i]^2
2*d*sum[i] * sum[j] + f[d][i] -... =d*(sum[j]^2+P[d-1][j])
2*sum[i]*sum[j]+f[d][i]/d-...=sum[j]^2+P[d-1][j];
P[d][i]= (sum[i]-sum[j])^2+ P[d-1][j]
2*sum[i] * sum[j] + P[d][i] -... = P[d-1][j]+sum[j]^2
*/
inline db slope(int a,int b,int d){return 1.00*(sum[a]*sum[a]-sum[b]*sum[b]+P[d-1][a]-P[d-1][b])/(1.00*(sum[a]-sum[b]));}
signed main(){
sf("%d%d",&n,&m);
for(int i=1;i<=n;++i)sf("%d",&sum[i]),sum[i]+=sum[i-1],P[1][i]=sum[i]*sum[i];
for(int d=2;d<=m;++d){
head=tail=0;
for(int i=1;i<=n;++i){
while(head<tail&&slope(q[head],q[head+1],d)<=2.00*sum[i])++head;
int j=q[head];
P[d][i]=(sum[i]-sum[j])*(sum[i]-sum[j])+P[d-1][j];
while(head<tail&&slope(q[tail-1],q[tail],d)>=slope(q[tail],i,d))--tail;
q[++tail]=i;
}
}
cout<<m*P[m-1][q[head]]+m*(sum[n]-sum[q[head]])*(sum[n]-sum[q[head]])-sum[n]*sum[n];
return 0;
}
by the way
请那位大佬分析一下为什么这样求wa了。。
#include<bits/stdc++.h>
using namespace std;
#define sf scanf
#define pf printf
#define ll long long
#define db double
const int N=3e3+5;
ll P[N][N],ans;
int sum[N],q[N],head,tail,n,m;
/*
f[d][i]=d*P[d-1][j]+d*(sum[i]-sum[j])^2-sum[i]^2
2*d*sum[i] * sum[j] + f[d][i] -... =d*(sum[j]^2+P[d-1][j])
2*sum[i]*sum[j]+f[d][i]/d-...=sum[j]^2+P[d-1][j];
P[d][i]= (sum[i]-sum[j])^2+ P[d-1][j]
2*sum[i] * sum[j] + P[d][i] -... = P[d-1][j]+sum[j]^2
*/
inline db slope(int a,int b,int d){return 1.00*(sum[a]*sum[a]-sum[b]*sum[b]+P[d-1][a]-P[d-1][b])/(1.00*(sum[a]-sum[b]));}
signed main(){
sf("%d%d",&n,&m);
for(int i=1;i<=n;++i)sf("%d",&sum[i]),sum[i]+=sum[i-1],P[1][i]=sum[i]*sum[i];
for(int d=2;d<=m;++d){
head=tail=0;
// pf("d: %d\n",d);
for(int i=1;i<=n;++i){
// pf("i: %d\n",i);
while(head<tail&&slope(q[head],q[head+1],d)<=2.00*sum[i])++head;
int j=q[head];
// pf("head:%d j:%d \n",head,j);
P[d][i]=(sum[i]-sum[j])*(sum[i]-sum[j])+P[d-1][j];
while(head<tail&&slope(q[tail-1],q[tail],d)>=slope(q[tail],i,d))--tail;
q[++tail]=i;
// pf("d :%d i: %d P[d][i]=: %lld\n",d,i,P[d][i]);
}
}
ans=1e10;
for(int j=m-1;j<n;++j){
ans=min(ans,(m*P[m-1][j]+m*(sum[n]-sum[j])*(sum[n]-sum[j])-sum[n]*sum[n]));
}
cout<<ans;
return 0;
}