D
e
s
c
r
i
p
t
i
o
n
\mathcal{Description}
Description
有n块土地,每块有A[i]泥土,现把其改造成B[i]泥土,有3种操作:
(1)花费X向任意土地增加1泥土;
(2)花费Y向任意土地减少1泥土;
(3)花费Z*|i-j|把土地i的1泥土运到土地j。问最小花费是多少。
A [ i ] , B [ i ] < = 100 , n < = 100 , X , Y , Z < = 1000 A[i],B[i]<=100,\\n<=100,\\X,Y,Z<=1000 A[i],B[i]<=100,n<=100,X,Y,Z<=1000
S
o
l
u
t
i
o
n
1
\mathcal{Solution_1}
Solution1
最
初
想
法
最初想法
最初想法
思考发现, 最开始土地分为两种类型 : 要求降低, 要求升高.
在两个不同类型的土地
i
,
j
i,j
i,j 之间, 若
X
+
Y
>
Z
∗
∣
i
−
j
∣
X+Y>Z*|i-j|
X+Y>Z∗∣i−j∣ 时, 则将泥土从
i
i
i 搬往
j
j
j 一定优于 直接升高降低.
于是按照此方法 贪心, 得到
50
p
t
s
50pts
50pts.
正
解
部
分
正解部分
正解部分
大概思想如上, 是因为我维护方法不对才拿了
50
p
t
s
50pts
50pts, 重点看实现部分.
实
现
部
分
实现部分
实现部分
对两种类型的土地分别建立两个 大根堆
Q
1
,
Q
2
Q_1,\ Q_2
Q1, Q2, 内部元素是 单位泥土,
(可以理解为
Q
1
Q_1
Q1 是囤积的泥土, 可以堆到其他土地上;
Q
2
Q_2
Q2 是筐, 可以将其他土地上的泥土倒到对应土地上),
从左往右边扫, 设当前位置为
i
i
i, 土地类型为 要求下降, 即可以将当前泥土堆到其他土地上.
将该地泥土分为
A
[
i
]
A[i]
A[i] 个单位泥土, 对每个单位泥土 单独处理,
对当前 要降低 的单位泥土, 有两种选择:
- 直接扔泥土, c o s t = X cost=X cost=X, 此时需要 Q 1 . p u s h ( i ∗ Z + X ) Q_1.push(i*Z + X) Q1.push(i∗Z+X)
- 从前方不同类型的土地 搬泥土, c o s t 2 = i ∗ Z − Q 2 . t o p . f i r s t cost_2 = i*Z-Q_2.top.first cost2=i∗Z−Q2.top.first,
- 从后方不同类型的土地 搬泥土,此时需要 Q 2 . p u s h ( i ∗ Z + c o s t 2 ) \ Q_2.push(i*Z+cost_2) Q2.push(i∗Z+cost2)
注意以上都需执行 A n s + = m i n ( c o s t , c o s t 2 ) Ans += min(cost,cost_2) Ans+=min(cost,cost2)., (弹出操作已省略).
时间复杂度
O
(
N
∗
10
∗
log
(
N
∗
10
)
)
O(N*10*\log(N*10))
O(N∗10∗log(N∗10))
S
o
l
u
t
i
o
n
2
\mathcal{Solution_2}
Solution2
可以使用
D
p
Dp
Dp,
设
F
[
i
,
j
]
F[i, j]
F[i,j] 表示 处理了
i
i
i 个第一类型的单位泥土,
j
j
j 个第二类型的单位泥土 所花费的最小价值,
F [ i , j ] = m i n { F [ i − 1 , j ] + X F [ i , j − 1 ] + Y F [ i − 1 , j − 1 ] + Z ∗ ∣ p o s i − p o s j ∣ F[i, j]= min\begin{cases} F[i-1, j] + X\\ F[i, j-1] + Y\\ F[i-1,j-1]+Z*∣pos_i-pos_j∣ \end{cases} F[i,j]=min⎩⎪⎨⎪⎧F[i−1,j]+XF[i,j−1]+YF[i−1,j−1]+Z∗∣posi−posj∣
时间复杂度 O ( ( N ∗ 10 ) 2 ) O((N*10)^2) O((N∗10)2)
C
o
d
e
\mathcal{Code}
Code
贪心代码.
#include<bits/stdc++.h>
#define reg register
const int maxn = 105;
const int inf = 0x7f7f7f7f;
int N;
int X;
int Y;
int Z;
int Ans;
int A[maxn];
int B[maxn];
std::priority_queue <int> Q1;
std::priority_queue <int> Q2;
void Work_1(int i){ // In, Up
int cost = inf;
if(!Q1.empty()){
int t = Q1.top();
int tmp = i*Z - t;
if(tmp < X) Q1.pop(), cost = tmp;
}
if(cost == inf) cost = X;
Q2.push(i*Z + cost); Ans += cost;
}
void Work_2(int i){ // Out, Down
int cost = inf;
if(!Q2.empty()){
int t = Q2.top();
int tmp = i*Z - t;
if(tmp < Y) Q2.pop(), cost = tmp;
}
if(cost == inf) cost = Y;
Q1.push(i*Z + cost); Ans += cost;
}
int main(){
scanf("%d%d%d%d", &N, &X, &Y, &Z);
for(reg int i = 1; i <= N; i ++) scanf("%d%d", &A[i], &B[i]);
for(reg int i = 1; i <= N; i ++)
for(reg int j = 1; j <= abs(B[i]-A[i]); j ++)
if(A[i] < B[i]) Work_1(i);
else Work_2(i);
printf("%d\n", Ans);
return 0;
}