NOIp提高组2016 Day2 T2 蚯蚓

洛谷原题链接
关于题目不多赘述

初始想法

因为每次需要取出最长的一条蚯蚓进行操作,所以下意识就想到了堆
第一问在取出是每次取出,第二问则是最终结果
但是如何处理每秒都会增长的q?
开设一个Add变量,表示所有蚯蚓的增长量,每次取出一条蚯蚓就将原量加上Add再进行处理, 放回堆中时还要再减去Add
因为切割会影响增长,所以每次切割完后放回堆钟的蚯蚓都要再减去q
总复杂度为O((n+m)log(n+m))只能得65分

看了题解后的想法

我们会发现蚯蚓的切割具有单调性:一只蚯蚓切割后会分为|px|和x-|px|两个部分,对于其中的任意一个部分,在某一时刻切割出的那只蚯蚓必然会比在它之后切割出来的蚯蚓要长
反证法可证明
考虑记录三个队列,分别存储未切割过的蚯蚓和切割成的两只蚯蚓,每次将蚯蚓插入对应的队尾。根据我们上面推论得出的单调性,每次取出三个队头的最大值即可,蚯蚓长度的增加和上述堆做法的处理方式相同,这样的总复杂为O(n+m)

 #include<cstdio>
 #include<algorithm>
using namespace std;
typedef long long ll;
const int inf = ~1u>>1;
const int maxn = 1e5 + 5, maxm = 7e6 + 5;
int n, m, q, u, v, t, Add;
int Q[3][maxm], qt[3], qw[3];
inline int get_num() {
    int num; char ch;
    while((ch = getchar()) < '0' || ch > '9');
    num = ch - '0';
    while((ch = getchar()) >= '0' && ch <= '9') 
        num = (num << 3) + (num << 1) + ch - '0';
    return num;
} 
inline void put_num(int x) {
    if(x > 9) put_num(x/10);
    putchar(x%10 + 48);
}
inline bool cmp(const int &x, const int &y) {
    return x > y;
}
inline int get_max() {
    int ret = -inf, k;
    for(int i = 0; i < 3; ++i) {
        if(qt[i] < qw[i] && ret < Q[i][qt[i]+1]) {
            ret = Q[i][qt[i]+1], k = i;
        }
    }
    qt[k]++;
    return ret;
}
int main() {
    n = get_num(); m = get_num(); q = get_num();
    u = get_num(); v = get_num(); t = get_num();
    for(int i = 1; i <= n; ++i) Q[0][++qw[0]] = get_num();
    sort(Q[0]+1, Q[0]+qw[0]+1, cmp);
    for(int i = 1; i <= m; ++i) {
        int x = get_max() + Add;
        if(i%t == 0) {
            put_num(x);
            putchar(i+t>m ? '\n' : ' ');
        }
        int l = (ll)x * u / v,
            r = x - l;
        Q[1][++qw[1]] = l - Add - q;
        Q[2][++qw[2]] = r - Add - q;
        Add += q;
    }
    if(t > m) putchar('\n');
    int tmp = n+m;
    for(int i = 1; i <= tmp; ++i) {
        int x = get_max() + Add;
        if(i%t == 0) {
            put_num(x);
            if(i+t <= tmp) {
                putchar(' ');
            }
        }
    }
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值