[NOIP2016] 蚯蚓


题目描述

这里写图片描述


输入格式

这里写图片描述


输出格式

输出到文件 earthworm.out
第一行输出[m/t]个整数,按时间顺序,依次输出第t秒,第2t秒,第3t秒……被切断蚯蚓(在被切断前)的长度。
这里写图片描述


样例数据

样例输入

输入样例#1:
3 7 1 1 3 1
3 3 2
输入样例#2:
3 7 1 1 3 2
3 3 2
输入样例#3:
3 7 1 1 3 9
3 3 2

样例输出

输出样例#1:
3 4 4 4 5 5 6
6 6 6 5 5 4 4 3 2 2
输出样例#2:
4 4 5
6 5 4 3 2
输出样例#3:
//空行
2


说明

【样例解释1】
在神刀手到来前:3只蚯蚓的长度为3,3,2。
1秒后:一只长度为3的蚯蚓被切成了两只长度分别为1和2的蚯蚓,其余蚯蚓的长度增加了1。最终4只蚯蚓的长度分别为(1,2),4,3。括号表示这个位置刚刚有一只蚯蚓被切断
2秒后:一只长度为4的蚯蚓被切成了1和3。5只蚯蚓的长度分别为:2,3,(1,3),4。
3秒后:一只长度为4的蚯蚓被切断。6只蚯蚓的长度分别为:3,4,2,4,(1,3)。
4秒后:一只长度为4的蚯蚓被切断。7只蚯蚓的长度分别为:4,(1,3),3,5,2,4。
5秒后:一只长度为5的蚯蚓被切断。8只蚯蚓的长度分别为:5,2,4,4,(1,4),3,5。
6秒后:一只长度为5的蚯蚓被切断。9只蚯蚓的长度分别为:(1,4),3,5,5,2,5,4,6。
7秒后:一只长度为6的蚯蚓被切断。10只蚯蚓的长度分别为:2,5,4,6,6,3,6,5,(2,4)。所以,7秒内被切断的蚯蚓的长度依次为3,4,4,4,5,5,6。7秒后,所有蚯蚓长度从大到小排序为6,6,6,5,5,4,4,3,2,2

【样例解释2】
这个数据中只有t=2与上个数据不同。只需在每行都改为每两个数输出一个数即可。
虽然第一行最后有一个6没有被输出,但是第二行仍然要重新从第二个数再开始输出。
【样例解释3】
这个数据中只有t=9与上个数据不同。
注意第一行没有数要输出,但也要输出一个空行。
这里写图片描述


题目分析

正常想法:堆+偏移(这个写起来比正解还麻烦。。。)
预计分数:80分
正解:
开三个队列,第一个队列储存没有被切得蚯蚓,第二个队列储存被切过得前一半蚯蚓,第三个队列储存被切过的后一半蚯蚓。
事先将第一个队列从大到小排序,便可以保证所有队列均有序(想一想,为什么?)
每次从三个队列中取出一个最大的切掉,同时将偏移量delta加着走,当然要保证队列里的元素是减了delta的。
为什么需要引入偏移量delta呢?因为我们要保持队列有序,如果手动排序就nlogn了,就成了暴力,因此需要delta来间接维护队列。
注意要开long long!


源代码

#include<algorithm>
#include<iostream>
#include<iomanip>
#include<cstring>
#include<cstdlib>
#include<vector>
#include<cstdio>
#include<cmath>
#include<queue>
using namespace std;
inline const int Get_Int() {
    int num=0,bj=1;
    char x=getchar();
    while(x<'0'||x>'9') {
        if(x=='-')bj=-1;
        x=getchar();
    }
    while(x>='0'&&x<='9') {
        num=num*10+x-'0';
        x=getchar();
    }
    return num*bj;
}
bool cmp(long long a,long long b) {
    return a>b;
}
int n,m,q,u,v,t,cnt=0;
long long a[8000005],Delta=0;
deque<long long>Q[4];
int main() {
    n=Get_Int();
    m=Get_Int();
    q=Get_Int();
    u=Get_Int();
    v=Get_Int();
    t=Get_Int();
    for(int i=1; i<=n; i++)a[i]=Get_Int();
    sort(a+1,a+n+1,cmp);
    for(int i=1; i<=n; i++)Q[1].push_back(a[i]);
    for(int i=1; i<=m; i++) {
        long long Max=-1e10,maxl;
        for(int j=1; j<=3; j++)
            if(!Q[j].empty()&&Q[j].front()>Max) {
                Max=Q[j].front();
                maxl=j;
            }
        Q[maxl].pop_front();
        Max+=Delta;
        if(i%t==0)printf("%lld ",Max);
        Delta+=q;
        long long Left=Max*u/v,Right=Max-Left;
        Q[2].push_back(Left-Delta);
        Q[3].push_back(Right-Delta);
    }
    putchar('\n');
    while(!Q[1].empty()||!Q[2].empty()||!Q[3].empty()) {
        cnt++;
        long long Max=-1e10,maxl;
        for(int i=1; i<=3; i++)
            if(!Q[i].empty()&&Q[i].front()>Max) {
                Max=Q[i].front();
                maxl=i;
            }
        Max+=Delta;
        if(cnt%t==0)printf("%lld ",Max);
        Q[maxl].pop_front();
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值