洛谷P2827 蚯蚓(隐藏的单调的队列)

本文详细解析了P2827蚯蚓问题的解题思路,通过模拟切蚯蚓过程,发现后切的蚯蚓比先切的短。文章介绍了如何将蚯蚓按长度排序并分为三部分,利用差分思想优化切割过程,最终实现高效的求解。

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

P2827 蚯蚓

题解
(不行,我先吐槽一下,因为少了两个等号我调了一个晚上!!!可恶啊(〃>皿<),35分到100分的差距!)

首先,我们可以先模拟一下切蚯蚓的过程,会发现,后切成蚯蚓肯定要比先切成蚯蚓短。假设现在有蚯蚓 a , b a,b a,b并且 L a &gt; L b L_a&gt;L_b La>Lb,对于第 i i i次切割,切割蚯蚓 a a a,长度为 L a L_a La,将其切割为 x = p ⋅ L a x=p\cdot L_a x=pLa y = L a − x y = L_a-x y=Lax,对于第 j ( i &lt; j ≤ m ) j(i&lt;j\leq m) j(i<jm)次切割,切割蚯蚓 b b b,将其切割为 x 1 = p ⋅ L b x_1=p\cdot L_b x1=pLb y 1 = L b − x 1 y_1 = L_b-x_1 y1=Lbx1,此时之前第 i i i次切割的两条蚯蚓的长度应该为 x + ( j − i ) x+(j-i) x+(ji) y + ( j − i ) y+(j-i) y+(ji),因此有
{ p ⋅ L a + ( j − i ) &gt; p ⋅ L b + ( j − i ) L a ⋅ ( 1 − p ) + ( j − i ) &gt; L b ⋅ ( 1 − p ) + ( j − i ) \begin{cases} p\cdot L_a+(j-i)&gt;p\cdot L_b+(j-i)\\\\ L_a\cdot (1-p)+(j-i)&gt;L_b\cdot(1-p)+(j-i)\end{cases} pLa+(ji)>pLb+(ji)La(1p)+(ji)>Lb(1p)+(ji)

因此我们可以利用这个规律,将蚯蚓分为三部分:

1.从大到小排好序的未切割的蚯蚓
2.每次切割完蚯蚓长度相对短的蚯蚓
3.每次切割完蚯蚓长度相对长的蚯蚓
然后每次切割的时候在这三队里面选择最长的蚯蚓切割即可。

还有一点就是对于每次切割时未被切割的蚯蚓会增加长度 q q q,因为每次增加的时候是固定的 q q q,因此我们可以利用差分思想,标记增量,每次入队的时候减去,查询的时候再加上。

#include<bits/stdc++.h>

using namespace std;
const int N = 7000010;
int n,m,q,u,v,t,a[N],b[N],c[N];

int main() {
#ifndef ONLINE_JUDGE
    freopen("input.in", "r", stdin);
#endif
    vector<int> ans;
    cin >> n >> m >> q >> u >> v >> t;
    for (int i = 0; i < n; ++i)
        cin >> a[i];
    int front1 = 0, rear1 = n, front2 = 0, rear2 = 0, front3 = 0, rear3 = 0;
    sort(a, a + n, greater<int>());
    int tmp, sum = 0;
    double p = 1.0 * u / v;
    for (int i = 1; i <= m; ++i) {
        if (front1 < rear1) {
            if (a[front1] >= max(b[front2], c[front3])) {
                tmp = a[front1++];
            } else if (b[front2] >= max(a[front1], c[front3])) {
                tmp = b[front2++];
            } else {
                tmp = c[front3++];
            }
        } else {
            if (b[front2] > c[front3])
                tmp = b[front2++];
            else
                tmp = c[front3++];
        }
        tmp += sum; //加上标记
        sum += q; //更新标记
        int x = floor(p * tmp), y = tmp - x;
        x -= sum, y -= sum;
        b[rear2++] = x, c[rear3++] = y;
        if (i % t == 0)
            cout << tmp << ' ';
    }
    puts("");
    for (int i = front1; i < rear1; ++i)
        ans.push_back(a[i]);
    for (int i = front2; i < rear2; ++i)
        ans.push_back(b[i]);
    for (int i = front3; i < rear3; ++i)
        ans.push_back(c[i]);
    sort(ans.begin(), ans.end(), greater<int>());
    for (int i = 0; i < ans.size(); ++i) {
        if ((i + 1) % t == 0)
            cout << ans[i] + sum << ' ';
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值