首页 > 代码库 > CF747D Winter Is Coming

CF747D Winter Is Coming

 题目链接:

http://codeforces.com/problemset/problem/747/D

题目大意:

接下来的n天内每天都有一个气温,如果某天的温度为负数,则必须使用冬季轮胎;而温度非负,则既可以使用冬季轮胎,也可以使用夏季轮胎。开始的时候车子上装的是夏季轮胎,如果连续两天使用的轮胎类型不同,则需要换胎。规定使用冬季轮胎的总天数不能超过k,问换胎的最少次数。(注:n天结束后车子上装的既可以是冬季轮胎,也可以是夏季轮胎)。

解题思路:

一开始想到dp+滚动数组。然而时间复杂度太高,查了tutorial发现可以贪心。具体来说就是:

1.当温度为负数的天数之和大于k时,无解。

2.否则令k减去温度为负数的天数之和。并求出所有连续的温度为负数的区段的个数cnt,此时换胎次数x最多为cnt*2。

3.求出所有连续的温度为非负数的区段,并将这样的区段的长度push到一个小顶堆中。先不考虑持续到第n天的非负区段(如果有的话),不要将这样的区段放入堆中(之后判断这种特殊情况)。也不必考虑从第1天开始持续到第一个负区段之前的非负区段,因为一开始车子上的是夏季轮胎,这样的区段不会影响最终结果。

4.当堆不空并且k大于等于堆顶元素的时候,将堆顶元素pop出来,同时将k减去堆顶元素,并且令x -= 2。(相当于贪心地合并掉非负区段)

5.考虑特殊情况:如果存在一个非负区段并且这个区段持续到第n天,并且此时k大于等于这个区段的长度,则可以x--(相当于最后一次不换回夏季轮胎,省掉一次换胎操作);或者最后一个负区段持续到第n天,这种情况也可以省掉一次换回夏季轮胎的操作,也要x--。总之,无论持续到n天的最后一个区段是负区段还是非负区段,都要x--。这样就得到了最终答案。

其实思路不是很难想,但是实现起来需要注意一些细节。

代码写得不是很漂亮:

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <queue>
  4 #include <functional>
  5 #include <vector>
  6 using namespace std;
  7 
  8 int a[200005], n, k;
  9 int find_non_negtive_start(int pos)
 10 {
 11     for (int i = pos; i < n; i++)
 12     {
 13         if (a[i] >= 0)
 14             return i;
 15     }
 16     return -1;
 17 }
 18 int find_non_negtive_end(int pos)
 19 {
 20     for (int i = pos; i < n; i++)
 21     {
 22         if (a[i] < 0)
 23             return i - 1;
 24     }
 25     return -1;
 26 }
 27 int find_negtive_start(int pos)
 28 {
 29     for (int i = pos; i < n; i++)
 30     {
 31         if (a[i] < 0)
 32             return i;
 33     }
 34     return -1;
 35 }
 36 int find_negtive_end(int pos)
 37 {
 38     for (int i = pos; i < n; i++)
 39     {
 40         if (a[i] >= 0)
 41             return i - 1;
 42     }
 43     return -1;
 44 }
 45 int main()
 46 {
 47     priority_queue<int, vector<int>, greater<int> > q;
 48     cin >> n >> k;
 49     int cnt = 0, cnt_negtive = 0;
 50     int start = -1, begin = -1;
 51     for (int i = 0; i < n; i++)
 52     {
 53         scanf("%d", &a[i]);
 54         if (a[i] < 0)
 55         {
 56             cnt++;
 57             if (begin == -1)
 58                 begin = i;
 59         }
 60         else
 61         {
 62             if (begin != -1 && start == -1)
 63                 start = i;
 64         }
 65     }
 66     if (cnt > k)
 67     {
 68         cout << "-1" << endl;
 69         return 0;
 70     }
 71     if (cnt == 0)
 72     {
 73         cout << "0" << endl;
 74         return 0;
 75     }
 76     if (start == -1)
 77     {
 78         cout << "1" << endl;
 79         return 0;
 80     }
 81     if (begin == -1)
 82     {
 83         cout << "0" << endl;
 84         return 0;
 85     }
 86     cnt_negtive = cnt;
 87     cnt = 0;
 88     while (1)
 89     {
 90         int pos = find_negtive_end(begin + 1);
 91         if (pos == -1)
 92         {
 93             cnt++;
 94             break;
 95         }
 96         cnt++;
 97         begin = find_negtive_start(pos + 1);
 98         if (begin == -1)
 99             break;
100     }
101     cnt *= 2;
102     int res = -1;
103     while (1)
104     {
105         int pos = find_non_negtive_end(start + 1);
106         if (pos == -1)
107         {
108             res = n - start;
109             break;
110         }
111         q.push(pos - start + 1);
112         start = find_non_negtive_start(pos + 1);
113         if (start == -1)
114         {
115             break;
116         }
117     }
118     k -= cnt_negtive;
119     while (!q.empty())
120     {
121         if (k >= q.top())
122         {
123             k -= q.top();
124             q.pop();
125             cnt -= 2;
126         }
127         else
128         {
129             break;
130         }
131     }
132     if (k >= res) 
133     {
134         cnt--;
135     }
136     cout << cnt << endl;
137     return 0;
138 }

 

CF747D Winter Is Coming