洛谷P2827 蚯蚓(NOIp2016) (BZOJ4721)

本文介绍了一种解决特定类型蚯蚓长度变化问题的方法,通过分析题目特点,采用数组记录长度差值的方式,避免了使用堆所带来的复杂度问题,实现了O(m)的时间复杂度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

技巧题

洛谷题目传送门
BZOJ题目传送门

初看时觉得用堆,但是m=7e6,貌似刚好卡log。于是只能另寻出路。

我们用堆的是要维护最大值,因为蚯蚓的长度每次都会变。
但是题目有这么一句话:

除了刚刚产生的两只新蚯蚓,其余蚯蚓的长度都会增加q(是一个非负整常数)。

也就是说,刚切的是不会涨长度的。而我们只需要它们之间的大小关系。因此我们只需考虑长度之间的差值。
那么,给所有蚯蚓的长度+q=给那两只的长度-q。
我们可以开三个数组,一个存开始时的蚯蚓,一个存切过后长度=[px]的蚯蚓,一个存长度=x-[px]的蚯蚓。

不难发现,这三个数组是分别递减的。
于是我们只需要每次在这三个数组的头取蚯蚓即可。输出时再加回去就行了。

时间复杂度 O(m) O ( m )

代码(BZOJ行末不能有空格,而且第二行不能有换行符。别问我怎么知道的):

#include<cstdio>
#include<cstring>
#include<algorithm>
#define MAXN 7100000
using namespace std;
struct earthworm{
    int p[MAXN+5];
    int r,w;
};
int n,m,q,u,v,t;
earthworm a,b,c;
inline char readc(){
    static char buf[100000],*l=buf,*r=buf;
    if (l==r) r=(l=buf)+fread(buf,1,100000,stdin);
    if (l==r) return EOF; return *l++;
}
inline int _read(){
    int num=0; char ch=readc();
    while (ch<'0'||ch>'9') ch=readc();
    while (ch>='0'&&ch<='9'){ num=num*10+ch-48; ch=readc(); }
    return num;
}
bool comp(int x,int y){
    return x>y;
}
int main(){
    n=_read(); m=_read(); q=_read(); u=_read(); v=_read(); t=_read();
    for (int i=1;i<=n;i++)
        a.p[++a.w]=_read();
    sort(a.p+1,a.p+n+1,comp);
    for (int i=1;i<=m;i++){
        int x=-0x7fffffff;
        if (a.r<a.w) x=max(a.p[a.r+1],x);
        if (b.r<b.w) x=max(b.p[b.r+1],x);
        if (c.r<c.w) x=max(c.p[c.r+1],x);
        if (i%t==0) printf("%d ",x+(i-1)*q);
        int px=(double)u/v*(x+(i-1)*q);
        if (a.r<a.w&&x==a.p[a.r+1]) a.r++;
        else if (b.r<b.w&&x==b.p[b.r+1]) b.r++;
             else c.r++;
        b.p[++b.w]=px-i*q; c.p[++c.w]=x-px-q;
    }
    printf("\n");
    int node=0;
    while (a.r<a.w||b.r<b.w||c.r<c.w){
        node++;
        int x=-0x7fffffff;
        if (a.r<a.w) x=max(a.p[a.r+1],x);
        if (b.r<b.w) x=max(b.p[b.r+1],x);
        if (c.r<c.w) x=max(c.p[c.r+1],x);
        if (node%t==0) printf("%d ",x+m*q);
        if (a.r<a.w&&x==a.p[a.r+1]) a.r++;
        else if (b.r<b.w&&x==b.p[b.r+1]) b.r++;
             else if (c.r<c.w) c.r++;
    }
    printf("\n");
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值