D
因为我太菜了,没看出这是一道DP,QAQ
状态表示: f [ i ] [ j ] f[i][j] f[i][j] 表示前 i i i 个 1 和前 j j j 个 0 匹配的最小代价。假设有 n 1 n_1 n1 个 1 和 n 2 n_2 n2 个0,那么最终的答案就是 f [ n 1 ] [ n 2 ] f[n_1][n_2] f[n1][n2]
状态转移:在求
f
[
i
]
[
j
]
f[i][j]
f[i][j] 时,考虑第
i
i
i 个 1 是否和第
j
j
j 个 0 匹配
如果第
i
i
i 个1 和第
j
j
j 个 0 匹配,那么此时的代价就是
f
[
i
−
1
]
[
j
−
1
]
+
∣
x
[
i
]
−
b
[
j
]
∣
f[i - 1][j - 1] + |x[i] - b[j]|
f[i−1][j−1]+∣x[i]−b[j]∣,这里
x
[
i
]
x[i]
x[i] 表示第
i
i
i 个 1 的位置,
b
[
j
]
b[j]
b[j] 表示第
j
j
j 个 0 的位置;
如果第 i i i 个 1 和第 j j j 个 0 不匹配,这时候要求 f [ i ] [ j ] f[i][j] f[i][j],那么第 i i i 个 1 只能和前面的 0 进行匹配了,所以只能和第 k , k ∈ [ i , i + 1 , . . . , j − 1 ] k, k \in [i, i + 1, ..., j - 1] k,k∈[i,i+1,...,j−1] 个 0 进行匹配,这里的范围比较重要
综上第
i
i
i 个 1 是和第
k
,
k
∈
[
i
,
i
+
1
,
.
.
.
,
j
]
k, k \in [i, i + 1, ..., j]
k,k∈[i,i+1,...,j]个 0 进行匹配,所以得到
f
[
i
]
[
j
]
=
m
i
n
(
f
[
i
−
1
]
[
k
−
1
]
+
∣
x
[
i
]
−
y
[
k
]
∣
)
,
k
∈
[
i
,
i
+
1
,
.
.
.
,
j
]
f[i][j] = min(f[i - 1][k - 1] + |x[i] - y[k]|),k \in[i, i + 1, ..., j]
f[i][j]=min(f[i−1][k−1]+∣x[i]−y[k]∣),k∈[i,i+1,...,j]
到了这一步,可以求出答案了,不过时间复杂度是
O
(
n
3
)
O(n^3)
O(n3) 的,因为需要枚举
i
,
j
,
k
i, j, k
i,j,k,所以需要进行优化
我是把 k 前面几个和后面几个列出来,观察发现
f
[
i
]
[
j
−
1
]
f[i][j - 1]
f[i][j−1] 的式子和这个很像:
f
[
i
]
[
j
−
1
]
=
m
i
n
(
f
[
i
−
1
]
[
k
−
1
]
+
∣
x
[
i
]
−
y
[
k
]
∣
)
,
k
∈
[
i
,
i
+
1
,
.
.
.
,
j
−
1
]
f[i][j - 1] = min(f[i - 1][k - 1] + |x[i] - y[k]|),k \in[i, i + 1, ..., j - 1]
f[i][j−1]=min(f[i−1][k−1]+∣x[i]−y[k]∣),k∈[i,i+1,...,j−1]
然后
f
[
i
]
[
j
−
1
]
f[i][j - 1]
f[i][j−1] 和
f
[
i
]
[
j
]
f[i][j]
f[i][j]只相差了
k
=
j
k = j
k=j 的情况,所以可以得到:
f
[
i
]
[
j
]
=
m
i
n
(
f
[
i
]
[
j
−
1
]
,
f
[
i
−
1
]
[
j
−
1
]
+
∣
x
[
i
]
−
y
[
j
]
∣
)
f[i][j] = min(f[i][j - 1], f[i - 1][j - 1] + |x[i] - y[j]|)
f[i][j]=min(f[i][j−1],f[i−1][j−1]+∣x[i]−y[j]∣)
完美的状态转移方程就完成了!
初始化:当没有 1 的时候,是不需要任何代价的,所以 f [ 0 ] [ j ] , j ∈ [ 0 , n 2 ] = 0 f[0][j], j \in [0, n2] = 0 f[0][j],j∈[0,n2]=0,就可以了!
下面是AC代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N = 5e3 + 17;
int f[N][N];
int a[N], b[N];
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int n, n1 = 0, n2 = 0;
cin >> n;
for(int i = 1; i <= n; ++i){
int x;
cin >> x;
if(x) a[++n1] = i;
else b[++n2] = i;
}
memset(f, 0x3f, sizeof f);
for(int i = 0; i < N; ++i){
f[0][i] = 0;
}
for(int i = 1; i <= n1; ++i){
for(int j = 1; j <= n2; ++j){
f[i][j] = min(f[i][j - 1], f[i - 1][j - 1] + abs(a[i] - b[j]));
}
}
cout << f[n1][n2];
return 0;
}