题解 P2827 【蚯蚓】

Solution 蚯蚓

题目大意:一开始有\(n\)只蚯蚓,你操作\(m\)次。每次抓最长的一只,记长度为\(x\),切成\(\lfloor px\rfloor\),\(x-\lfloor px\rfloor\)两只放回去,同时除这两只外的所有蚯蚓长度增加\(q\),问每次切断蚯蚓的长度,\(m\)次操作后所有蚯蚓的长度

队列


首先我们来解决除新增外集体增加\(q\)的问题,我们可以维护一个增量\(delta\),表示所有的蚯蚓的长度都要增加\(delta\),新增的两只蚯蚓不加\(q\),我们就将它长度减\(q\)后再处理即可,因此在处理中可能有负数

不难想到一个简单粗暴的模拟思路,用一个大根堆,每次取最大的切了后丢回去同时维护增量\(delta\)。但是这样会带一个\(log\),无法承受

关键在于切断后新增的两条蚯蚓都比原来的短,因此我们每次取出来的蚯蚓长度是递减的(不考虑增量\(delta\)),用序列合并这题思路,用一个队列\(Q_1\)存储原来的\(n\)条蚯蚓(排个序就好),\(Q_2\)存储切成\(\lfloor px\rfloor\)的蚯蚓,\(Q_3\)存储切成\(x-\lfloor px\rfloor\)的蚯蚓,每次从三个队列队头取最大值,切成的蚯蚓分别丢进\(Q_2\),\(Q_3\)维护\(delta\)即可

#include <algorithm>
#include <cstdio>
#include <cctype>
#include <queue>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 100;
inline int read(){
    int x = 0;char c = getchar();
    while(!isdigit(c))c = getchar();
    while(isdigit(c))x = x * 10 + c - '0',c = getchar();
    return x;
}
queue<ll> Q[4];
int val[maxn],n,m,q,u,v,t;
ll delta;
inline int findmax(){
    int res = 0;
    for(int i = 1;i <= 3;i++)
        if(!Q[i].empty() && (!res || Q[i].front() > Q[res].front()))res = i;
    return res;
}
inline ll cut(ll x){return 1ll * u * x / v;}
inline void solve(int tim){
    ll x = Q[findmax()].front();Q[findmax()].pop();
    if(tim % t == 0)printf("%lld ",x + delta);
    Q[2].push(cut(x + delta) - delta - q);Q[3].push(x - cut(x + delta) - q);
    delta += q;
}
int main(){
    n = read(),m = read(),q = read(),u = read(),v = read(),t = read();
    for(int i = 1;i <= n;i++)val[i] = read();
    sort(val + 1,val + 1 + n);
    for(int i = n;i >= 1;i--)Q[1].push(val[i]);
    for(int i = 1;i <= m;i++)solve(i);
    putchar('\n');
    for(int i = 1;i * t <= n + m;i++){
        for(int j = 1;j <= t - 1;j++)
            Q[findmax()].pop();
        printf("%lld ",Q[findmax()].front() + delta);
        Q[findmax()].pop();
    }
    putchar('\n');
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/colazcy/p/11711460.html
今日推荐