zoukankan      html  css  js  c++  java
  • 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 }
  • 相关阅读:
    UIimageView和UIimage的小区别
    transform
    block的一些注意事项
    category与协议的不同
    类扩展和category的小区别
    category的概念
    OC中的类扩展
    Java学习 第三章 java基础(三)
    Java学习 第三章 java基础(二)
    Java学习 第三章 java基础(一)
  • 原文地址:https://www.cnblogs.com/wangyiming/p/6204725.html
Copyright © 2011-2022 走看看