CF998B Cutting 题解 DP+贪心
题目链接:http://codeforces.com/problemset/problem/998/B
题目描述
有很多东西是可以被切割的,比如——树、纸张或者绳子。在这道题目里面你需要切割一个整数序列。
现在告诉你一个整数序列,在这个整数序列里面有一些数,它们可能是奇数,也可能是偶数。
给你一个固定的预算(因为切割是有成本的),你需要尽可能多地将这个整数序列切分成一系列连续子序列,
使得每一个连续子序列中的 奇数元素的个数 和 偶数元素的个数 相同。
比如,给你一个整数序列 [4,1,2,3,4,5,4,4,5,5] ,你可以将其切割两次变成
[4,1 | 2,3,4,5 | 4,4,5,5] 。其中,[4,1] 、 [2,3,4,5] 以及 [4,4,5,5] 这三个连续子序列中包含的奇数个数等于偶数个数。
如果你要将第 i 个元素和第 i+1 个元素之间切一刀,我们假设第 i 个元素对应的数值为 x ,第 j 个元素对应的数值为 y ,那么你需要消耗 |x-y| 个比特币。
(|x-y| 表示 x-y 的差的绝对值)。
而你的预算只有 B 个比特币,所以你需要计算一下在最多消耗 B 个比特币的情况下,你最多可以切几次。
输入格式
输入的第一行包含两个整数 n (2<=n<=100)和 B(1<=B<=100),分别表示整数序列中元素的个数和你最多可用的比特币的数量。
输入的第二行包含 n 个整数,用于表示整数序列中的元素:a1,a2,……,an(1<=ai<=100)。
输出格式
输出一个整数,用于表示在最多消耗 B 个比特币的情况下,你最多可以切几刀,使得每一个切出来的连续子序列中包含相同的奇偶元素。
样例输入1
6 4
1 2 5 10 15 20
样例输出1
1
样例输入2
4 10
1 3 2 4
样例输出2
0
样例输入3
6 100
1 2 3 4 5 6
样例输出3
2
样例解释
对于样例1,我们可以在 2 和 5 之间切割一刀,消耗 3 个比特币;
对于样例2,我们无法切割;
对于样例3,我们可以在 2 和 3 之间 以及 4 和 5 之间切割一刀,消耗 1+1=2 个比特币。
问题分析
这道题目涉及的算法是“DP”+“贪心”,可以用 dp+sort 或者 dp+heap 来做。
首先我们假设 n 个元素的坐标从 1 到 n ,他们分别对应 a[1] 到 a[n] 。
然后我们开一个输出 cc[] ,cc[i] 用于表示从 a[1] 到 a[i] 这 i 个数中奇数个数减去偶数个数之差。
那么对于 1 到 n-1 范围内的 i ,如果 cc[i] == 0 ,那么它这个位置就是可以切割的,切割的成本是 abs(a[i+1]-a[i]) 。
dp+sort解法:
我们将 1 到 n-1 范围内的所有满足 cc[i]==0 条件的 i 对应的 abs(a[i+1]-a[i]) 放入一个数组中,然后将这个数组从小到大排序,每次取出一个数计数器cnt++,同时B减去这个数,直到B不够用为止;
dp+heap(堆)解法:
我们首先构造一个最小堆(可以用 priority_queue 模拟),然后将 1 到 n-1 范围内的所有满足 cc[i]==0 条件的 i 对应的 abs(a[i+1]-a[i]) 放入最小堆中1,然后每次从最小堆中取出堆顶元素,计数器cnt++,同时B减去这个数,直到B不够用为止。
1、下面的代码演示了 dp+sort 的操作:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 110;
int n, B, cnt, a[maxn], cc[maxn];
vector<int> vec;
int main() {
cin >> n >> B;
for (int i = 1; i <= n; i ++) {
cin >> a[i];
cc[i] = cc[i-1] + (a[i] % 2 ? 1 : -1);
}
for (int i = 1; i < n; i ++) if (!cc[i]) vec.push_back(abs(a[i+1]-a[i]));
sort(vec.begin(), vec.end());
for (vector<int>::iterator it = vec.begin(); it != vec.end(); it ++) {
if (*it > B) break;
B -= *it;
cnt ++;
}
cout << cnt << endl;
return 0;
}
2、下面的代码演示了 dp+heap 的操作:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 110;
int n, B, cnt, a[maxn], cc[maxn];
priority_queue<int, vector<int>, greater<int> > que;
int main() {
cin >> n >> B;
for (int i = 1; i <= n; i ++) {
cin >> a[i];
cc[i] = cc[i-1] + (a[i] % 2 ? 1 : -1);
}
for (int i = 1; i < n; i ++) if (!cc[i]) que.push(abs(a[i+1]-a[i]));
while (!que.empty()) {
int u = que.top();
que.pop();
if (u > B) break;
B -= u;
cnt ++;
}
cout << cnt << endl;
return 0;
}