Ac.Wing 133蚯蚓 进阶指南P56 题解

写在前面的话:
这道题久违了
个人感觉这个题目的质量还是相当不错的,结合了队列和数学,难度上在Ac.Wing属于橙题范围,做这个题的时候发现的主要问题在于:

  • 一些数学公式的推导思路和理解还要去训练
  • 对于整体偏移和通过偏移量求值的问题的理解

下面给题解:
题解:
这个题目可以去用最朴素的方法解决:就是说我们定义一个偏移量,每一次从队列中取出一个最大值,然后把他分得的 f l o o r ( p x ) floor(px) floor(px) x − f l o o r ( p x ) x - floor(px) xfloor(px)全部减去q后加入集合中,然后每次我们要取他们的值,只需要加上整个集合的偏移量就可以了。这里可以理解为一种延迟叠加。但是这种方法复杂度太高,我们需要再优化。
下面开始数学推导:
假设现在集合中有 x 1 x_1 x1 x 2 x_2 x2两种长度的蚯蚓,我们令 x 1 > = x 2 x_1 >= x_2 x1>=x2,现在将 x 1 x_1 x1取出,得到 f l o o r ( p x 1 ) , x 1 − f l o o r ( p x 1 ) floor(px_1),x_1 - floor(px_1) floor(px1),x1floor(px1),同时 x 2 − > x 2 + q x_2 -> x_2 + q x2>x2+q,现在我们假设 x 2 + q x_2 + q x2+q被取出,那么分成 f l o o r ( p x 2 + p q ) , ( x 2 + q ) − f l o o r ( p x 2 + p q ) floor(px_2 + pq),(x_2 + q) - floor(px_2 + pq) floor(px2+pq),(x2+q)floor(px2+pq).
同时 x 1 x_1 x1也有了相应的变动: f l o o r ( p x 1 ) + q , x 1 + q − f l o o r ( p x 1 ) floor(px_1) + q,x_1 + q - floor(px_1) floor(px1)+q,x1+qfloor(px1)
我们可以得出: f l o o r ( p x 1 ) + q = f l o o r ( p x 1 + q ) > = f l o o r ( p x 1 + p q ) > = f l o o r ( p x 2 + p q ) floor(px_1) + q = floor(px_1 + q) >= floor(px_1 + pq) >= floor(px_2 + pq) floor(px1)+q=floor(px1+q)>=floor(px1+pq)>=floor(px2+pq)
同时由于 ( x 1 − x 2 ) > = p ( x 1 − x 2 ) , x 1 − p x 1 > = x 2 − p x 2 (x_1 - x_2) >= p(x_1 - x_2),x_1 - px_1 >= x_2 - px_2 (x1x2)>=p(x1x2),x1px1>=x2px2
于是有 x 1 − f l o o r ( p x 1 ) + q > = x 2 − f l o o r ( p x 2 ) + q > = ( x 2 + q ) − f l o o r ( p x 2 + p q ) x_1 - floor(px_1) + q>= x_2 - floor(px_2) + q >= (x_2 + q) - floor(px_2 + pq) x1floor(px1)+q>=x2floor(px2)+q>=(x2+q)floor(px2+pq)
所以我们可以发现,对于先后取出的两个数,后取出的数新产生的两个数不可能比之前分得得数+q后大。这就意味着,我们可以直接在 f l o o r ( p x ) floor(px) floor(px) x − f l o o r ( p x ) x - floor(px) xfloor(px),以及之前没有取过的数中取最大值就可以,可以采用三个队列存储数据。注意偏移量的设置!
AC代码:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<queue>
#include<map>
#include<vector>
#include<bitset>
#include<cstring>
#include<algorithm>
#define ll long long
#define INF 0x3f3f3f3f
#define inf -1e12

using namespace std;

queue<int > q1; //存floor(px)
queue<int > q2; //存x - floor(px)
priority_queue<int ,vector<int >,less<int > > q3; //存数组中剩下的
ll n,m,q,u,v,t;

ll calc(ll x)
{
    ll a = inf,b = inf,c = inf,ans = 0;
    if(!q1.empty()) a = q1.front() + x * q;
    if(!q2.empty()) b = q2.front() + x * q;
    if(!q3.empty()) c = q3.top() + x * q;
    ans = max(a,max(b,c));
    if(ans == a) q1.pop();
    else if(ans == b) q2.pop();
    else q3.pop();
    return ans;
}

int main()
{
    scanf("%lld%lld%lld%lld%lld%lld",&n,&m,&q,&u,&v,&t);
    for(ll i = 1ll;i <= n;i++){
        int x;
        cin >> x;
        q3.push(x);
    }
    for(ll i = 0ll;i < m;i++){
        ll x = calc(i);
        // cout << x << endl;
        if((i + 1) % t == 0) printf("%lld ",x);
        ll a1 = floor(x * u / v),a2 = x - floor(x * u / v);
        q1.push(a1 - (i + 1) * q);
        q2.push(a2 - (i + 1) * q);
    }
    printf("\n");
    for(ll i = 1ll;i <= n + m;i++){
        ll x = calc(m);
        if(i % t == 0) printf("%lld ",x); 
    }
    printf("\n");
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CUCKyrie

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值