题目描述
分析
状态分析
发现有三个量:
- 电线杆
- 该电线杆的高度
- 当时的最小费用
所以令 d p i , j dp_{i,j} dpi,j表示第 i i i杆电线杆高度为 j j j时所花的最小费用即可
暴力DP分析
分析:
0
0
0
状态转移方程
d
p
i
,
j
=
m
i
n
{
d
p
i
−
1
,
k
+
c
∗
∣
j
−
k
∣
+
(
j
−
h
i
)
2
}
dp_{i,j}=min\{dp_{i-1,k}+c*|j-k|+(j-h_i)^2\}
dpi,j=min{dpi−1,k+c∗∣j−k∣+(j−hi)2}
嗯,枚举一下当前电线杆的高度(
j
j
j)和前一根电线杆的高度(
k
k
k)即可
优化分析
上一个的复杂度是
O
(
n
∗
H
m
a
x
2
)
O(n*{H_{max}}^2)
O(n∗Hmax2)
而
H
m
a
x
=
100
H_{max}=100
Hmax=100,
n
=
100000
n=100000
n=100000,不爆才怪……(好像LGOJ评测机很好的样子)
首先,
j
−
h
i
j-h_i
j−hi是一个定值,所以可以暂时不管
然后,看到有一个
∣
j
−
h
i
∣
|j-h_i|
∣j−hi∣,绝对值,数学遇到了该怎么办?分类讨论。
所以
d
p
i
,
j
=
m
i
n
{
d
p
i
−
1
,
k
+
c
∗
k
}
−
c
∗
j
+
(
j
−
h
i
)
2
(
k
>
=
j
)
dp_{i,j}=min\{dp_{i-1,k}+c*k\}-c*j+(j-h_i)^2(k>=j)
dpi,j=min{dpi−1,k+c∗k}−c∗j+(j−hi)2(k>=j)
d
p
i
,
j
=
m
i
n
{
d
p
i
−
1
,
k
−
c
∗
k
}
+
c
∗
j
+
(
j
−
h
i
)
2
(
k
<
j
)
dp_{i,j}=min\{dp_{i-1,k}-c*k\}+c*j+(j-h_i)^2(k<j)
dpi,j=min{dpi−1,k−c∗k}+c∗j+(j−hi)2(k<j)
诶?枚举
k
k
k时,
j
j
j为一个定值。这样一来,
j
,
k
j,k
j,k就可以同时枚举!
搞一个预处理,显然
d
p
1
,
j
=
(
j
−
h
1
)
2
dp_{1,j}=(j-h_1)^2
dp1,j=(j−h1)2,于是,下面就可以通过
j
,
k
j,k
j,k同时枚举而优化,关键代码如下
for i 2 to n {
long long Minn=INF,Minn1=INF;
for j 0 to h[i]
Minn=Min dp[i-1][j]-c*j;
for j h[i] to maxh
Minn=Min dp[i-1][j]-c*j;
dp[i][j]=Min Minn+c*j+(j-h[i])*(j-h[i]);
for j 100 downto j>=h[i] {
Minn1=Min dp[i-1][j]+c*j;
dp[i][j]=Min Minn1-c*j+(j-h[i])*(j-h[i]);
}
}
End…
代码
暴力+ O 2 O2 O2靠LG强评测机能过的代码
// luogu-judger-enable-o2
#include<map>
#include<set>
#include<list>
#include<queue>
#include<deque>
#include<stack>
#include<ctime>
#include<cmath>
#include<vector>
#include<bitset>
#include<cstdio>
#include<cctype>
#include<string>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<iomanip>
#include<iostream>
#include<algorithm>
using namespace std;
#define reg register
template <typename T>
inline T read() {
T a=0; char c=getchar(),f=1;
while(c<'0'||c>'9') {
if(c=='-') f=-f;
if(c==-1) return c;
c=getchar();
}
while(c>='0'&&c<='9') a=(a<<1)+(a<<3)+(c^48),c=getchar();
return a*f;
}
template <class T>
inline int write(T x) {
if(x<0) x=(~x)+1, putchar('-');
if(x/10) write(x/10);
return putchar(x%10|48);
}
template <class T>
inline int write(T x,char c) {
return write(x)&&putchar(c);
}
template <class T>
inline T Max(T a,T b) { return a>b?a:b; }
template <class T>
inline T Min(T a,T b) { return a<b?a:b; }
template <class T>
inline T Abs(T a) { return a<0?-a:a; }
int n=read<int>(),c=read<int>();
long long h[100001];
long long dp[100001][101];
long long ans=0x3f3f3f3f;
long long mh;
int main() {
for(reg int i=1;i<=n;i++)
mh=Max(mh,h[i]=read<long long>());
memset(dp,0x3f,sizeof dp);
for(reg int i=0;i<=mh;i++)
dp[1][i]=(i-h[1])*(i-h[1]);
for(reg int i=2;i<=n;i++) {
for(reg int j=h[i];j<=mh;j++) {
for(reg int k=h[i-1];k<=mh;k++) {
dp[i][j]=Min(dp[i][j],dp[i-1][k]+c*Abs(j-k)+(j-h[i])*(j-h[i]));
}
}
}
for(reg int i=1;i<=mh;i++) {
ans=Min(ans,dp[n][i]);
}
write(ans);
}
正解代码
#include<cstdio>
#include<cstring>
using namespace std;
#define reg register
template <typename T>
inline T read() {
T a=0; char c=getchar(),f=1;
while(c<'0'||c>'9') {
if(c=='-') f=-f;
if(c==-1) return c;
c=getchar();
}
while(c>='0'&&c<='9') a=(a<<1)+(a<<3)+(c^48),c=getchar();
return a*f;
}
template <class T>
inline int write(T x) {
if(x<0) x=(~x)+1, putchar('-');
if(x/10) write(x/10);
return putchar(x%10|48);
}
template <class T>
inline int write(T x,char c) {
return write(x)&&putchar(c);
}
template <class T>
inline T Min(T a,T b) { return a<b?a:b; }
const long long INF=1e15;
int n=read<int>(),c=read<int>();
long long h[100001];
long long dp[100001][101];
long long ans=INF;
long long mh;
int main() {
for(reg int i=1;i<=n;i++)
h[i]=read<long long>();
memset(dp,0x3f,sizeof dp);
for(reg int i=h[1];i<=100;i++)
dp[1][i]=(i-h[1])*(i-h[1]);
for(reg int i=2;i<=n;i++) {
long long Minn=INF,Minn1=INF;
for(int j=0;j<=h[i];j++)
Minn=Min((dp[i-1][j]-c*j),Minn);
for(int j=h[i];j<=100;j++) {
Minn=Min(Minn,dp[i-1][j]-c*j);
dp[i][j]=Min(dp[i][j],Minn+c*j+(j-h[i])*(j-h[i]));
}
for (int j=100;j>=h[i];j--) {
Minn1=Min(Minn1,(dp[i-1][j]+c*j));
dp[i][j]=Min(dp[i][j],Minn1-c*j+(j-h[i])*(j-h[i]));
}
}
for(reg int i=1;i<=100;i++)
ans=Min(ans,dp[n][i]);
write(ans);
}