蚯蚓 NOIP2016 提高组 Day2 T2

3 篇文章 0 订阅

描述

本题中,我们将用符号⌊c⌋表示对c向下取整,例如:⌊3.0⌋=⌊3.l⌋=⌊3.9⌋=3。
蛐蛐国最近蚯蚓成灾了!隔壁跳蚤国的跳蚤也拿蚯蚓们没办法,蛐蛐国王只好去请神刀手来帮他们消灭蚯蚓。
蛐蛐国里现在共有n只蚯蚓(n为正整数)。每只蚯蚓拥有长度,我们设第i只蚯蚓的长度为ai(i=1, 2, …, n),并保证所有的长度都是非负整数(即:可能存在长度为0的蚯蚓)。
每一秒,神刀手会在所有的蚯蚓中,准确地找到最长的那一只(如有多个则任选一个)将其切成两半。神刀手切开蚯蚓的位置由常数p (是满足0 < p < l的有理数)决定,设这只蚯蚓长度为x,神刀手会将其切成两只长度分别为⌊px⌋和x - ⌊px⌋的蚯蚓。特殊地,如果这两个数的其中一个等于0,则这个长度为0的蚯蚓也会被保留。此外,除了刚刚产生的两只新蚯蚓,其余蚯蚓的长度都会增加q (是一个非负整常数)。
蛐蛐国王知道这样不是长久之计,因为蚯蚓不仅会越来越多,还会越来越长。蛐蛐国王决定求助于一位有着洪荒之力的神秘人物,但是救兵还需要m秒才能到来…… (m为非负整数)
蛐蛐国王希望知道这m秒内的战况。具体来说,他希望知道:
m秒内,每一秒被切断的蚯蚓被切断前的长度(有m个数)
m秒后,所有蚯蚓的长度(有n + m个数)。
蛐蛐国王当然知道怎么做啦!但是他想考考你……
格式

输入格式

第一行包含六个整数n,m,q,u,v,t,其中:n,m,q的意义见【问题描述】;u,v,t均为正整数;你需要自己计算p = u/v (保证0 < u < v) t是输出参数,其含义将会在 【输出格式】中解释。
第二行包含n个非负整数,为a1, a2, …, an,即初始时n只蚯蚓的长度。
同一行中相邻的两个数之间,恰好用一个空格隔开。
保证 1<=n<=10^5,0 <= m <= 7 x 10^6, 0 < u < v <= 10^9,0 <= q <= 200, 1 <= t <= 71, 0 <= ai <= 10^8。
输出格式

第一行输出⌊m/t ⌋个整数,按时间顺序,依次输出第t秒,第2t秒,第3t秒,……被切断蚯蚓(在被切断前)的长度。
第二行输出⌊(n+m)/t⌋个整数,输出m秒后蚯蚓的长度;需要按从大到小的顺序,依次输出排名第t,第2t,第3t,…… 的长度。
同一行中相邻的两个数之间,恰好用一个空格隔开。即使某一行没有任何数需要输出,你也应输出一个空行。
请阅读样例来更好地理解这个格式。

样例1

样例输入1

3 7 1 1 3 1
3 3 2

样例输出1

3 4 4 4 5 5 6
6 6 6 5 5 4 4 3 2 2

样例2

样例输入2

3 7 1 1 3 2
3 3 2

样例输出2

4 4 5
6 5 4 3 2

样例3

样例输入3

3 7 1 1 3 9
3 3 2

样例输出3

//这是空行
2

限制

【子任务】
测试点1~3满足m = 0。
测试点4 ~ 7满足n, m <= 1,000。
测试点8 ~ 14满足q = 0,其中测试点8~9还满足m <= 10^5。
测试点15 ~ 18满足m <= 3 x 10^5。
测试点19 ~ 20没有特殊的约定,参见原始的数据范围。
测试点1 ~ 12,15 ~ 16还满足v <= 2,这意味着u, v的唯一可能的取值是 u = 1, v = 2,即p = 0.5。这可能会对解决问题有特殊的帮助。

每个测试点的详细数据范围见下表。
这里写图片描述

思路:首先稍安勿躁把题意看明白。我们看到每次找一个长度最大的蚯蚓来切,很容易想到堆,但mlogn不太好说,还有n会随操作次数而增大,所以是不行的。所以我们可以开三个队列来模拟,一个保存原蚯蚓长度,一个保存被切后较长蚯蚓的长度,还有一个保存被切后较短蚯蚓的长度,这样就可以保持单调性了(为什么单调的呢?首先,对于一段单调序列,让序列中的每个数都加上同一个数单调性不变,其次,把一个单调序列中的每一个数按相同比例拆开后分别放到另外两个序列中,另外两个序列依然满足单调性)。同时对于对于每段时间蚯蚓的增长长度,显然每次让所有蚯蚓都加一个数是不可能的,我们可以记录一下每段蚯蚓的入队时间,在取出时直接让当前时间减去入队时间再乘每秒增长长度就可以了。

题解:

#include<iostream>
#include<cstdio>
#include<queue>
#include<algorithm>
using namespace std;
struct cc{
    long long len,ti;
};
queue<cc>q1;
queue<cc>q2;
queue<cc>q3;
long long cmp(long long aa,long long bb)
{
    return aa>bb;
}
long long a[100000+10];
long long n,m,q,u,v,t;
long long ask(long long i)
{
    long long num1=-1,num2=-1,num3=-1;
    if(!q1.empty()) num1=q1.front().len+q*(i-q1.front().ti-1);
    if(!q2.empty()) num2=q2.front().len+q*(i-q2.front().ti-1);
    if(!q3.empty()) num3=q3.front().len+q*(i-q3.front().ti-1);
    if(num1>=num2&&num1>=num3)
    {
        q1.pop(); return num1;
    }
    if(num2>=num1&&num2>=num3)
    {
        q2.pop(); return num2;
    }
    if(num3>=num1&&num3>=num2)
    {
        q3.pop(); return num3;
    }
}
int main()
{
    scanf("%lld%lld%lld%lld%lld%lld",&n,&m,&q,&u,&v,&t);
    for(long long i=1;i<=n;i++)
    {
        scanf("%lld",&a[i]);
    }
    sort(a+1,a+n+1,cmp);//排序保证从大到小
    for(long long i=1;i<=n;i++)
    {
        q1.push((cc){a[i],0});
    }
    for(long long i=1;i<=m;i++)
    {
        long long now=ask(i);
        if(i%t==0)
        {
            printf("%lld ",now);
        }
        if(now*u/v>now-now*u/v)//不能直接算出u/v,可能会有精度问题
        {
            q2.push((cc){now*u/v,i});
            q3.push((cc){now-now*u/v,i});
        }
        else
        {
            q3.push((cc){now*u/v,i});
            q2.push((cc){now-now*u/v,i});
        }
    }
    printf("\n");
    for(long long i=1;i<=n+m;i++)
    {
        long long now=ask(m+1);
        if(i%t==0)
        {
            printf("%lld ",now);
        }
    }
    return 0;
} 
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值