Noip2016 提高d2 蚯蚓 解题报告

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_33468963/article/details/70176527

题目:

有n条蚯蚓,在每一秒i (i<=m) 时会有以下操作:
最长的蚯蚓(长度为max)会被砍成max*q 和 max-max*q 两段,
每一条蚯蚓(除了被砍的两条)会长长q单位长度。在此处q=u/v且0 < q < 1

求 当i秒(i%t == 0) 时被切蚯蚓的长度
m秒后第i (i%t == 0) 长 蚯蚓的长度

输入样例#1:(n,m,q,u,v,t和a[i])
3 7 1 1 3 1
3 3 2
输出样例#1:
3 4 4 4 5 5 6
6 6 6 5 5 4 4 3 2 2

数据范围:对于100%的数据
保证1 <= n <= 10^5, 0 < m < 7*10^6,
0 < u < v < 10^9,0 <= q <= 200,
1 < t < 71,0 < ai < 10^8。

这数据范围明显是为了卡常数的
那么priority_queue呢? mlog(m) = 1.6*10^8
事实证明只有60分。。。
毕竟这道题连一些写得不好看的O(n)算法都能卡掉

这还香港记者?

于是想到了手动维护单调队列O(n)算法
先对所以长度跑一遍 O(n)的 std::sort() 使其单调下降
接下来将新蚯蚓分别塞入队列1和队列2
在不考虑蚯蚓变长的情况下,被切蚯蚓是越切越短的,因此新队列不需要维护就是单调的。
但因为两条蚯蚓相对的长度不能确定,所以要开两个新队列。每次选择最长蚯蚓时只用在三个队列的队头中取出最大值就可以了。

代码不难实现,只是在 x = max * u / v 时int会溢出,要转为(long long)
然后可能要写读入优化 (毕竟我的1s=998ms)
怕 std::queue 可能会被卡 手写了对列

贴代码:

#include <cstdio>
#include <algorithm>
#define N 10000000

int q,u,v,que[3][N],m,i,j,time,h[3],t[3],Q;

inline bool cmp(int c1,int c2) {return c1 > c2;}
inline void read(int &sum) {
    char c;
    for (c=getchar();c < '0' || c > '9';c=getchar());
    for (sum = 0;c >= '0' && c <= '9';c=getchar()) sum = sum * 10 + c - 48;
}

int main() {
    read(t[0]);  read(m);  read(q);  read(u);  read(v);  read(time);
    for (i=0;i<t[0];i++) read(que[0][i]);
    std::sort(que[0],que[0]+t[0],cmp);
    for (i=1;i<=m;i++) {
        int rt = -1, max = 0x80000000;
        for(j=0;j<3;j++) if(h[j] < t[j] && que[j][h[j]] > max) max = que[ rt=j ][h[j]];
        h[rt]++;
        max += Q;
        Q += q;
        rt = (long long)max * u / v;
        que[1][t[1]++] = rt - Q;  que[2][t[2]++] = max - rt - Q;
        if(!(i % time)) printf("%d ", max);
    } putchar('\n');

    for (i=1;i <= t[0] + m;i++) {
        int rt = 0, max = 0x80000000;
        for (j=0;j<3;j++) if (h[j] < t[j] && que[j][h[j]] > max) max = que[ rt=j ][h[rt]];
        if (!(i % time)) printf("%d ",max + Q);
        h[rt]++;
    } putchar('\n');
}

猜你喜欢

转载自blog.csdn.net/qq_33468963/article/details/70176527