[NOIP2016][优先队列]蚯蚓

题目梗概

n只蚯蚓,有一个神刀手他每t秒会选择一个长度最大的蚯蚓x,切成px和x-px两段(如果出现0也视为存活),每秒除了被切的蚯蚓之外的所有蚯蚓都会增长q.

询问,m秒内,每t秒被切断的蚯蚓切断前的长度。

m秒后,所有蚯蚓的长度。

蚯蚓长度向下取整 [2.9]->[2]  [3.1]->[3]

 

思考

惭愧的是,去年在考场这个题目我居然奇迹般的爆0了。

所以题目要怎么写呢?

  1. 首先每次取最长的蚯蚓这个操作,一定需要优先队列(不然你每次操作之后再去排序一遍吗?)
  2. 其次我们可以用一个Lazy标记,在每次堆中元素取出的时候进行操作,就不再需要对每个蚯蚓进行加和操作了。
  3. 如果我们把切割后的两个蚯蚓看成两个序列,那么它们都呈现出单调递减的性质。(先切的蚯蚓一定长,后切的蚯蚓一定短。在比率一定的情况下,前者一定大于后者)
  4. 所以,我们需要一个大根堆和两个队列来维护。

感觉题目思维难度还是有的,一开始我只写了一个60分的做法(大根堆维护),在瞄了一眼题解区之后,发现大佬们还是太强了Orz。

对了,请不要忘了读入。算法的时间复杂度是(N+M)

#include <cstdio>
#include <algorithm>
#include <cmath>
typedef long long ll;
const int N = 1e5+5,M =7e6+5;
const int Max = 2147483647;
int n,m,q,u,v,t,Lazy;
int Q[3][M],Head[3],Tail[3];

//读入 
inline int Read()
{
    char ch; int res = 0; bool f = true;
    while (((ch = getchar()) < '0' || ch > '9') && ch != '-');
    if (ch == '-') f = false; 
     else res = ch - '0';
    while ((ch = getchar()) >= '0' && ch <= '9')
     res = (res << 3) + (res << 1) + ch - '0';
    return f? res : -res;
}


//输出 
inline void Out(int x)
{
    if (x < 0)
     x = -x, putchar('-'); 
    if (x > 9) Out(x / 10);
    putchar(x % 10 + 48); 
}

inline bool CMP(const int &x,const int &y) {
    return x>y;
}

//求三个队列的最大值 
inline int GetMax(){
    int res = - Max,k;
    for(int i=0;i<3;++i) 
        if(Head[i]<Tail[i] && res<Q[i][Head[i]+1]) res = Q[i][Head[i]+1],k=i;
    Head[k]++;
    return res;
}

int main(){
    n = Read();
    m = Read();
    q = Read();
    u = Read();
    v = Read();
    t = Read();
    for(int i=1;i<=n;++i) Q[0][++Tail[0]] = Read();
    std::sort(Q[0]+1,Q[0]+Tail[0]+1,CMP);
    for(int i=1;i<=m;++i){
        int x = GetMax() + Lazy;
        if(i%t==0) Out(x),putchar(i + t > m ? '\n' : ' '); 
        int l = (ll)x * u / v,r = x - l;
        Q[1][++Tail[1]] = l - Lazy - q;
        Q[2][++Tail[2]] = r - Lazy - q;
        Lazy+=q;
    }
    if(t>m) putchar('\n');
    int ans = n+m;
    for(int i=1;i<=ans;++i){
        int x = GetMax() + Lazy;
        if(i%t==0) {
            Out(x);
            if(i+t<=ans) putchar(' ');
        }
    }
    return 0;
}

 

转载于:https://www.cnblogs.com/OIerLYF/p/7300141.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值