D. Armchairs (dp)
题目大意:
有一排座位,其中有
n
2
\frac{n}{2}
2n的座位有人坐(值为1),其余为0,要求让每个有人做的地方都转移到没人坐的地方,每个人只能转移一次,且每次操作的代价为
a
b
s
(
i
−
j
)
abs(i - j)
abs(i−j),要求总代价最小。
思路:
一开始看到题,感觉数据很小,可以贪心暴力,记录有人和没人坐的位置,然后分别标记为
x
1
,
x
2
,
x
3
,
x
4.....
x
n
x1,x2,x3,x4.....xn
x1,x2,x3,x4.....xn,
y
1
,
y
2
,
y
3
y
4....
y
n
y1,y2,y3y4....yn
y1,y2,y3y4....yn,这样答案最佳就应该是
∑
i
=
1
n
(
x
i
−
y
i
)
\sum_{i=1}^{n}(xi - yi)
∑i=1n(xi−yi) 。(当然啊,好兄弟,这可是div. 2的D题啊,你这样未免有点不知好歹),果然wa了。看其他大佬的题解发现,其实这样的思路在有座的人数为偶数时,是没有办法得出最优解的。
因此,我们另辟蹊径。
准备操作相同,记录1,0的位置。两个数组,最优解仍然是
∑
i
=
1
n
(
x
i
−
y
i
)
\sum_{i=1}^{n}(xi - yi)
∑i=1n(xi−yi),那么我们想应该就是用dp来写了,其实只有两种情况。
首先
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j]代表的是前
i
i
i个1与前
j
j
j个0之间的匹配的最优解。
情况一
当第
j
j
j个0和第
i
i
i个1进行匹配即
d
p
[
i
]
[
j
]
=
m
i
n
(
d
p
[
i
]
[
j
]
,
d
p
[
i
−
1
]
[
j
−
1
]
+
a
b
s
(
i
−
j
)
)
dp[i][j] = min(dp[i][j],dp[i-1][j- 1] + abs (i-j))
dp[i][j]=min(dp[i][j],dp[i−1][j−1]+abs(i−j))
情况二
当第
j
j
j个0和第
i
i
i个1不进行匹配即
d
p
[
i
]
[
j
]
=
m
i
n
(
d
p
[
i
]
[
j
]
,
d
p
[
i
]
[
j
−
1
]
)
dp[i][j] = min(dp[i][j],dp[i][j- 1])
dp[i][j]=min(dp[i][j],dp[i][j−1])
#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
#include<map>
#include<cmath>
#include<iomanip>
#include<queue>
using namespace std;
typedef long long ll;
const int p = 1e9 + 7;
typedef pair<int, int> pii;
const int N = 1e6+10;
int dp[5005][5005];
int a[N], b[N];
int main() {
int n;
cin >> n;
int m = 1, k = 1;
memset(dp, 0x3f, sizeof dp);
for (int i = 1; i <= n; i++) {
int x;
cin >> x;
if (!x)b[m++] = i;
else a[k++] = i;
dp[0][i] = 0;
}
dp[0][0] = 0;
for (int i = 1; i <= k; i++) {
for (int j = 1; j <= m; j++) {
dp[i][j] = min(dp[i][j - 1], dp[i - 1][j - 1] + abs(a[i] - b[j]));
}
}
cout << dp[k][m] << endl;
}