Codeforces I. Producing Snow(优先队列)

时间:2019-08-11
本文章向大家介绍Codeforces I. Producing Snow(优先队列),主要包括Codeforces I. Producing Snow(优先队列)使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

题目描述:

C. Producing Snow
time limit per test
1 second
memory limit per test
256 megabytes
input
standard input
output
standard output

Alice likes snow a lot! Unfortunately, this year’s winter is already over, and she can’t expect to have any more of it. Bob has thus bought her a gift — a large snow maker. He plans to make some amount of snow every day. On day i he will make a pile of snow of volume Vi and put it in her garden.

Each day, every pile will shrink a little due to melting. More precisely, when the temperature on a given day is Ti, each pile will reduce its volume by Ti. If this would reduce the volume of a pile to or below zero, it disappears forever. All snow piles are independent of each other.

Note that the pile made on day i already loses part of its volume on the same day. In an extreme case, this may mean that there are no piles left at the end of a particular day.

You are given the initial pile sizes and the temperature on each day. Determine the total volume of snow melted on each day.
Input

The first line contains a single integer N (1 ≤ N ≤ 105) — the number of days.

The second line contains N integers V1, V2, …, VN (0 ≤ Vi ≤ 109), where Vi is the initial size of a snow pile made on the day i.

The third line contains N integers T1, T2, …, TN (0 ≤ Ti ≤ 109), where Ti is the temperature on the day i.
Output

Output a single line with N integers, where the i-th integer represents the total volume of snow melted on day i.
Examples
Input
Copy

3
10 10 5
5 7 2

Output

5 12 4

Input
Copy

5
30 25 20 15 10
9 10 12 4 13

Output

9 20 35 11 25

Note

In the first sample, Bob first makes a snow pile of volume 10, which melts to the size of 5 on the same day. On the second day, he makes another pile of size 10. Since it is a bit warmer than the day before, the first pile disappears completely while the second pile shrinks to 3. At the end of the second day, he has only a single pile of size 3. On the third day he makes a smaller pile than usual, but as the temperature dropped too, both piles survive till the end of the day.

思路:

题目是说,每天造出一堆雪,同时所有堆雪每天融化一点,如果融完了这堆雪就没了,求每一天的所有堆雪的融雪量。刚开始,模拟嘛,就见一个链表,每个节点模拟一堆雪,融完就删节点,比数组标记起来会快一点。每次从头统计一下融雪量。但是这样做太too young too simple了,数据量稍大一点就会超时。因为每次都要遍历一遍链表,最坏的情况是没有雪融完,链表越来越长,要遍历\(1+2+3+...+10^5\approx10^{10}\),不潮湿?超时!而且我还中间因为链表指针没搞清楚,在删除链表末的节点时漏了处理一个指向链表尾的重要指针,一直莫名错误,改了好久,放个代码。

#include <cstdio>
#define max_n 100005
using namespace std;
int N;
int V[max_n];
int T[max_n];
struct Node
{
    Node* nxt;
    int vol;
};
Node* head;
Node* p;
inline void read(int& x)
{
    x=0;
    int f=0;
    char ch=getchar();
    while('0'>ch||ch>'9')
    {
        if(ch=='-')
            f=1;
        ch=getchar();
    }
    while('0'<=ch&&ch<='9')
    {
        x=10*x+ch-'0';
        ch=getchar();
    }
    x=f?-x:x;
}
inline Node* del(Node* fro,Node* ite)
{
    Node* nxt = ite->nxt;
    /*cout << "vol" << ite->vol << endl;
    if(nxt==NULL)
    {
        printf("Yes\n");
    }*/
    if(nxt==NULL)
    {
        p = fro;
    }
    fro->nxt = nxt;
    ite->nxt = NULL;
    delete ite;
    ite = nxt;
    return ite;
    //cout << "ite->nxt " << ite->vol << endl;
}
#pragma optimize(2) 
int main()
{
    head = new Node;
    head->nxt = NULL;
    p = head;
    read(N);
    for(int i = 0; i<N; i++)
    {
        read(V[i]);
    }
    for(int j = 0; j<N; j++)
    {
        read(T[j]);
    }
    for(int i = 0; i<N; i++)
    {

        Node* node = new Node;
        node->vol = V[i];
        node->nxt = NULL;
        p->nxt = node;
        p = node;
        long long reduce = 0;
        Node* ite = head->nxt;
        Node* fro = head;
        while(ite!=NULL)
        {
            //cout << "T " << T[i] << endl;
            //cout << "ite " << ite->vol << endl;
            if(ite->vol<=T[i])
            {
                reduce =(long long) reduce + ite->vol;
                ite = del(fro,ite);
                //cout << "ite nxt " << ite->vol << endl;
            }
            else
            {
                reduce = (long long) reduce + T[i];
                ite->vol -= T[i];
                fro = ite;
                ite = ite->nxt;
            }
        }
        printf("%I64d ",reduce);
    }

    return 0;
}

然后就想什么限时一秒肯定有简便(正确)做法,想到了二分查找雪堆最弱(最容易消掉)的那一个,但好像排序的话会毁掉时间,而且因为生产的时间不同,每堆雪的抗融能力不能仅仅通过雪堆大小衡量。又想能不能预处理一下数组然后可以直接得出结果。怎么预处理?误打误撞想到了前缀和。因为每堆雪的消亡只与它和之后的时间有关,那岂不是要对于每一堆雪计算一个前缀和,然后陷入了思索。

其实我是没想出正解的,因为看了题解也没看懂。。现在好像有点懂了。思路大概是这样:先计算出每天消雪量的前缀和,使用优先队列(从小到大),然后每次把这一天的雪堆与前一天的消雪前缀和之和(思考一下为什么是这样的?)加入队列。每次比较一下队列最小值跟当前消雪量前缀和。这个比较有什么意义?首先要明白当前消雪量前缀和有什么意义,它表示包括今天之前的所有天本应该消去的雪量。当前队列最小值表示到今天为止最多能承受的消雪量,为什么?因为队列最小值是某天的雪量加上那天之前的雪量前缀和。最小值小于当前前缀和就说明从那个某天开始生产出来的那堆雪到了今天已经要消完了。于是把这些堆的雪消完,统计总共的消雪量。队列里留下的就是还没消完的雪堆能承受的最大消雪量,给他们也统计下今天应该消掉的雪,加到前面的统计量里,就得到了今天的实际消雪量。到了以后某天就可能会发现今天生产的雪在那天承受不住了,也要消完了,就会在那天消完今天的雪,排出队列。

代码:

#include <iostream>
#include <queue>
#define max_n 100005
using namespace std;
int N;
int V[max_n];
int T[max_n];
long long sum[max_n];
priority_queue<long long,vector<long long>,greater<long long> > que;
int main()
{
    cin >> N;
    for(int i = 1;i<=N;i++)
    {
        cin >> V[i];
    }
    for(int i = 1;i<=N;i++)
    {

        long long ans = 0;
        cin >> T[i];
        sum[i] = sum[i-1]+T[i];
        que.push(sum[i-1]+V[i]);
        while(!que.empty()&&que.top()<=sum[i])
        {
            ans += que.top()-sum[i-1];
            que.pop();
        }
        //cout << "sum[i]-sum[i-1] " << sum[i]-sum[i-1] << endl;
        ans += (sum[i]-sum[i-1])*que.size();
        cout << ans << " ";
    }
    return 0;
}

参考文章:

HOrchard,Codeforces 923B Producing Snow(优先队列),https://blog.csdn.net/HOrchard/article/details/79594634

原文地址:https://www.cnblogs.com/zhanhonhao/p/11336437.html