http://codeforces.com/contest/747/problem/D
大概的思路就是找到所有两个负数夹着的线段,优先覆盖最小的长度。使得那时候不用换鞋,是最优的。
但是这里有个坑点,就是最后一段,如果最后一段的长度和中间某一段的长度相等,那么应该优先覆盖中间那段,因为中间的那些,如果没覆盖,则换鞋2次,而最后的那一段,换鞋只需一次。
22 11
1 -1 1 2 3 -1 1 2 3 4 5 6 7 -1 1 2 3 4 -1 1 2 3
答案是4
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <algorithm> #include <assert.h> #define IOS ios::sync_with_stdio(false) using namespace std; #define inf (0x3f3f3f3f) typedef long long int LL; #include <iostream> #include <sstream> #include <vector> #include <set> #include <map> #include <queue> #include <string> const int maxn = 2e5 + 20; int a[maxn]; struct node { int val, id; node(int vval, int iid) : val(vval), id(iid) {} bool operator < (const struct node & rhs) const { if (val != rhs.val) return val < rhs.val; else return id < rhs.id; } }; vector<int>pos; vector<int>dis; set<struct node>ss; bool vis[maxn]; void work() { int n, k; cin >> n >> k; for (int i = 1; i <= n; ++i) { cin >> a[i]; if (a[i] < 0) pos.push_back(i); } if (k < pos.size()) { cout << -1 << endl; return; } if (pos.size() == 0) { cout << 0 << endl; return; } for (int i = 1; i < pos.size(); ++i) { dis.push_back(pos[i] - pos[i - 1] - 1); ss.insert(node(pos[i] - pos[i - 1] - 1, i - 1)); } int lef = k - pos.size(); for (set<struct node> :: iterator it = ss.begin(); it != ss.end(); ++it) { // cout << it->val << endl; if (lef >= it->val) { // cout << "ff" << endl; lef -= it->val; vis[it->id] = true; } else break; } int ans = 1; for (int i = 0; i < dis.size(); ++i) { if (vis[i]) continue; ans += 2; } if (lef < n - pos.back()) { ans += 1; } cout << ans << endl; } int main() { #ifdef local freopen("data.txt", "r", stdin); // freopen("data.txt", "w", stdout); #endif work(); return 0; }