洛谷 2827 [NOIP2016] 蚯蚓 队列模拟

该博客主要解析了洛谷NOIP2016竞赛中关于蚯蚓切割问题的解决方案。文章讨论了如何通过堆模拟实现85分的暴力解法,以及如何利用三个单调队列实现O(n log n + m)的时间复杂度优化,达到100分的正解。博主强调了在维护单调队列时的细节,并指出在处理过程中需要设置最大整数作为inf值。

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

题目:

https://www.luogu.org/problemnew/show/2827

首先一个蚯蚓被切割后,其他蚯蚓会增加q => 这个蚯蚓-q;
每次操作将此蚯蚓-q,然后最后统一+q * m即可;

85分暴力:
用堆模拟就行了;O(m log n)

100分正解:
O(n log n + m)
三个单调队列维护,第一个存初始蚯蚓,第二个存切割后的第一段,第三个存切割后的第二段,这是单调递减的,因为前面在切割前必然大于后面的,所以切割后也大于后面的;

注意inf需要赋为MAX int;

暴力:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;

priority_queue<int>Q;
int n,m,q,t,x,delta,num,cnt,tot,u1,u2,S;
int ans[6000001];
double u,v;



void solve()
{
    cin>>n>>m>>q>>u>>v>>t;
    for(int i=1;i<=n;i++) x=read(),Q.push(x);
    for(int i=1;i<=m;i++)
    {
        S=Q.top();
        Q.pop();
        if(i % t==0) ans[++num]=S+tot;
        u1=(S+tot)*u/v,u2=(S+tot)-u1;
        Q.push(u1-q-tot),Q.push(u2-q-tot);
        tot+=q;
    }
    for(int i=1;i<=num;i++) printf("%d ",ans[i]);
    cout<<'\n';
    while(!Q.empty())
    {
        S=Q.top();
        Q.pop(),cnt++;
        if(cnt % t==0) printf("%d ",S+tot);
    }
    return;
}
int main()
{
    solve();
    return 0;
}

正解:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
queue<int>Q[4];
int n,m,t,q,p,tot,inf=2147483642;
double u,v;
int a[1000001];
bool cmp(int a,int b)
{
    return a>b;
}

int get()
{
    int ans=0,a=-inf,b=-inf,c=-inf;
    if(!Q[1].empty()) a=Q[1].front();
    if(!Q[2].empty()) b=Q[2].front();
    if(!Q[3].empty()) c=Q[3].front();
    if((a>b && a>c) || (a==b && a>c) || (a==c && a>b))
        ans=Q[1].front(),Q[1].pop();
    else if((b>a && b>c) || (b==c && b>a))
        ans=Q[2].front(),Q[2].pop();
    else if(c>a && c>b)
        ans=Q[3].front(),Q[3].pop();
    else if(c==a && c==b)
        ans=Q[3].front(),Q[3].pop();
    return ans;

}

void solve()
{
    cin>>n>>m>>q>>u>>v>>t;
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    sort(a+1,a+n+1,cmp);
    for(int i=1;i<=n;i++) Q[1].push(a[i]);
    for(int i=1;i<=m;i++)
    {
        int S=get();
        if(i % t == 0) printf("%d ",S+tot);
        int u1=(S+tot)*u/v,u2=S+tot-u1;
        Q[2].push(u1-tot-q),Q[3].push(u2-tot-q);
        tot+=q;
    }
    cout<<'\n';
    for(int i=1;i<=m+n;i++)
    {
        int S=get();
        if(i % t==0) printf("%d ",S+tot);
    }
    return;
}


int main()
{
    solve();
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值