133. 蚯蚓

在这里插入图片描述

题意:

相当于维护一个集合,支持查询最大值、删除最大值、插入新的值。时间卡的贼紧!!!!!!!!!!我不记得我T了几次了都

思路:

根据输入输出以及n、m的数据范围可以知道,需要在每秒进行切割时找出当前最大值,这时发现枚举和堆、单调队列等查找/维护最大值的方法是超时的。这时就有三个队列q1、q2和q3,如果q1开始时单调递减,每次取出最大值,然后将这个蚯蚓分开,把其中大的一部分压入q2,小的一部分压入q3,显然,此时q1、q2和q3都是单调递减的(所以每次的取出操作就可以是:在q1、q2、q3的队首取出最大的一个)。
这时你会产生一个新疑问:怎样让蚯蚓生长呢?
我们发现,暴力将每次每只蚯蚓的长度加上q是不现实的,所以定义一个del,用来表示蚯蚓增长的长度,del初始时为零,每过一秒加上一个q。然后我们可以这样想:在每一秒初,最长的蚯蚓被切开;在这一秒过程中,其他蚯蚓增长了q;在这一秒末,最长的蚯蚓被切成两半,分别压入数组中:
为什么是一个加del和一个减del的操作呢?数学证明:如果第a秒(此时del=(a-1)q)初取出一个长为s的蚯蚓,那么它的实际长度是(s+(a-1)q),它会被切成两半s1和s2在第a+1末被放回去,s1、s2就是这两条新蚯蚓的初始长度,而放回去的是s1-a×q和s2-a×q。如果在第b+1秒初s1-a×q被取了出来,这时它会加上b×q成为s1-a×q+b×q。而在第a秒末到第b+1秒初中间有b-a秒,s1的长度应该是初始长度s1加上增加的长度(b-a)q,即s1+(b-a)q=s1-a×q+b×q。说白了就是让s1,s2把给他们吃的q吐出来。

AC代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 7e6+10;
inline int read() {
    int x=0,f=1; char ch=getchar();
    while(ch<'0' || ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
    while(ch>='0'&&ch<='9') { x=(x<<3)+(x<<1)+(ch^48); ch=getchar(); }
    return x * f;
}
int n,m,q,u,v,t,del;   
int h=1,h1=1,h2=1,t1,t2;    
int s[N],c1[N],c2[N];   
priority_queue<int> pq;
bool cmp(int a,int b) {
    return a > b;
}
int main()
{
    n = read(), m = read(), q = read(), u = read() ,v = read() ,t = read();
    double p = (double)u/(double)v;
    for(int i=1;i<=n;++i) s[i] = read();
    sort(s+1, s+1+n, cmp);//第一个队列用初始元素从小到大排序
    for(int i=1;i<=m;++i) {
        int tp,a1,a2;//tp为从三个队列头中选到的最大值
        if(h > n-1) c1[h1]>c2[h2] ? tp=c1[h1++] : tp=c2[h2++];//每只蚯蚓都被切过才比较
        else if(s[h]>=c1[h1] && s[h]>=c2[h2]) tp = s[h++];  
        else if(s[h]<=c1[h1] && c2[h2]<=c1[h1]) tp = c1[h1++];
        else tp = c2[h2++];
        tp += del; a1 = floor(p*(double)tp); a2 = tp - a1;//先加del再切模拟所有都长长了del
        del += q; a1 -= del; a2 -= del;
        c1[++t1] = a1, c2[++t2] = a2;//c1,c2存切完后的
        if(i%t==0) printf("%d ",tp);
    }
    putchar('\n');
    //把结果弄在优先队列里输出
    for(int i=h;i<=n;++i) pq.push(s[i]);
    for(int i=h1;i<=t1;++i) pq.push(c1[i]);
    for(int i=h2;i<=t2;++i) pq.push(c2[i]);
    int i = 0;
    while(pq.size()) {
        ++i; 
        if(i%t==0) printf("%d ",pq.top()+del); 
        pq.pop();
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值