农场主
题目链接:SSL 2238
题目大意
有 n 个 0 或 1 的数,然后你可以把它分成 k 个区间,每个区间的费用就是 0 个数乘 1 个数。
要你最小化总费用。
思路
就直接 DP。
设
f
i
,
j
f_{i,j}
fi,j 为前
i
i
i 个数,划分成
j
j
j 个区间的最小费用。
(
b
l
a
c
k
i
,
w
h
i
t
e
i
black_i,white_i
blacki,whitei 分别为
1
∼
i
1\sim i
1∼i 一共有多少个
1
/
0
1/0
1/0,前缀和求)
f
i
,
j
=
min
k
=
1
j
−
1
{
f
i
−
1
,
k
+
(
b
l
a
c
k
j
−
b
l
a
c
k
k
)
∗
(
w
h
i
t
e
j
−
w
h
i
t
e
k
)
}
f_{i,j}=\min\limits_{k=1}^{j-1}\{f_{i-1,k}+(black_j-black_k)*(white_j-white_k)\}
fi,j=k=1minj−1{fi−1,k+(blackj−blackk)∗(whitej−whitek)}
然后就好了。
代码
#include<cstdio>
#include<cstring>
#include<iostream>
#define rr register
#define ll long long
using namespace std;
int n, K;
ll f[601][601];
int col[1001];
int black[1001], white[1001];
int main() {
// freopen("farmer.in", "r", stdin);
// freopen("farmer.out", "w", stdout);
scanf("%d %d", &n, &K);
for (int i = 1; i <= n; i++) {
scanf("%d", &col[i]);
if (col[i] == 1) black[i] = 1;
else white[i] = 1;
black[i] += black[i - 1];
white[i] += white[i - 1];
}
memset(f, 0x7f, sizeof(f));
f[0][0] = 0;
for (rr int i = 1; i <= K; i++) {
for (rr int j = 1; j <= n; j++)
for (rr int k = 0; k < j; k++)
f[i][j] = min(f[i][j], f[i - 1][k] + 1ll * ((black[j] - black[k]) * (white[j] - white[k])));
}
printf("%lld", f[K][n]);
fclose(stdin);
fclose(stdout);
return 0;
}