zoukankan      html  css  js  c++  java
  • 【bzoj4721】【noip2016】蚯蚓

    题目描述

    本题中,我们将用符号⌊c⌋表示对c向下取整,例如:⌊3.0⌋=⌊3.1⌋=⌊3.9⌋=3。

    蛐蛐国最近蚯蚓成灾了!隔壁跳蚤国的跳蚤也拿蚯蚓们没办法,蛐蛐国王只好去请神刀手来帮他们消灭蚯蚓。

    蛐蛐国里现在共有n只蚯蚓(n为正整数)。每只蚯蚓拥有长度,我们设第i只蚯蚓的长度为ai(i=1, 2, ..., n),并保证所有的长度都是非负整数(即:可能存在长度为0的蚯蚓)。

    每一秒,神刀手会在所有的蚯蚓中,准确地找到最长的那一只(如有多个则任选一个)将其切成两半。神刀手切开蚯蚓的位置由常数p (是满足0<p<1的有理数)决定,设这只蚯蚓长度为x,神刀手会将其切成两只长度分别为⌊px⌋和x - ⌊px⌋的蚯蚓。特殊地,如果这两个数的其中一个等于0,则这个长度为0的蚯蚓也会被保留。此外,除了刚刚产生的两只新蚯蚓,其余蚯蚓的长度都会增加q (是一个非负整常数)。

    蛐蛐国王知道这样不是长久之计,因为蚯蚓不仅会越来越多,还会越来越长。蛐蛐国王决定求助于一位有着洪荒之力的神秘人物,但是救兵还需要m秒才能到来...... (m为非负整数)

    蛐蛐国王希望知道这m秒内的战况。具体来说,他希望知道:

    • m秒内,每一秒被切断的蚯蚓被切断前的长度(有m个数)
    • m秒后,所有蚯蚓的长度(有n + m个数)。

    蛐蛐国王当然知道怎么做啦!但是他想考考你......


    输入

    第一行包含六个整数n,m,q,u,v,t,其中:n,m,q的意义见【问题描述】;u,v,t均为正整数;你需要自己计算p = u/v (保证0<u<v) t是输出参数,其含义将会在 【输出格式】中解释。

    第二行包含n个非负整数,为a1, a2, ..., an,即初始时n只蚯蚓的长度。

    同一行中相邻的两个数之间,恰好用一个空格隔开。

    保证 1<=n<=10^5,0 <= m <= 7 x 10^6, 0 < u < v <= 10^9,0 <= q <= 200, 1 <= t <= 71, 0 <= ai <= 10^8。


    输出

    第一行输出个整数,按时间顺序,依次输出第t秒,第2t秒,第3t秒,……被切断蚯蚓(在被切断前)的长度。

    第二行输出个整数,输出m秒后蚯蚓的长度;需要按从大到小的顺序,依次输出排名第t,第2t,第3t,…… 的长度。

    同一行中相邻的两个数之间,恰好用一个空格隔开。即使某一行没有任何数需要输出,你也应输出一个空行。

    请阅读样例来更好地理解这个格式。


    样例输入1

    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

    样例输入2

    3 7 1 1 3 2
    3 3 2

    样例输出2

    4 4 5
    6 5 4 3 2

    样例输入3

    3 7 1 1 3 9
    3 3 2

    样例输出3

    2



     

    题解

    80分做法:建立一个大根堆,堆顶元素就是最大的元素,切成两段后再放入堆中。但是每秒蚯蚓的长度都会增加,是否需要修改堆里元素的值?其实并不需要,每次取出最大元素后,将最大值还原,例如现在是第t秒,最大值是max,那么这个最大值还原后就应该为 max + ( t-1 ) * q,将这个长度分成两端,再减去 t * q ,再加入堆中。堆可以用STL,代码很好实现。

    80分代码:

    #include<cmath>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    #define ll long long
    
    const int maxn=1e5+5;
    const int maxm=7e6+50;
    
    ll heap[maxm+maxn],x1,x2,x,ans1[maxm],ans2[maxn+maxm],a[maxn];
    int m,q,u,v,t,len,n,o;
    
    void put(int d){
        int now,next;
        heap[++len]=d;
        now=len;
        while (now>1){
            next=now>>1;
            if (heap[now]<=heap[next])return;
            swap(heap[now],heap[next]);
            now=next;
        }
    }
    
    int get(){
        int now,next,res;
        res=heap[1];
        heap[1]=heap[len--];
        now=1;
        while (now*2<=len){
            next=now*2;
            if (next<len && heap[next+1]>heap[next])
            next++;
            if (heap[now]>=heap[next])    
            return res;
            swap(heap[now],heap[next]);
            now=next;
        }
        return res;
    }
    
    template<typename T>void read(T& aa){
        char cc; ll ff;aa=0;cc=getchar();ff=1;
        while((cc<'0'||cc>'9')&&cc!='-') cc=getchar();
        if(cc=='-') ff=-1,cc=getchar();
        while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar();
        aa*=ff;
    }
    
    int main(){
        read(n),read(m),read(q),read(u),read(v),read(t);
        for(int i=1;i<=n;i++) read(a[i]),put(a[i]);
        for(int i=1;i<=m;i++){
            x=get();x=x+(i-1)*q;ans1[i]=x;
            x1=int(x*u/v);
            x2=x-x1;
            x1-=q*i;
            x2-=q*i;
            put(x1),put(x2);
        }
        if(t>m) cout<<endl;
        else {
            for(int i=1;i<=m/t;i++){
                o+=t;
                cout<<ans1[o]<<" ";
            }
            cout<<endl;
        }
        for(int i=1;i<=n+m;i++) ans2[i]=get();
        o=0;
        for(int i=1;i<=(m+n)/t;i++){
            o+=t;
            cout<<ans2[o]+m*q<<" ";
        }
        return 0;
    }

    100分:80分的做法需要维护最大值,多了一个log,于是被卡。如何不用维护最大值?

    开3个队列,q1,q2,q3。q1存原 a[ i ] ,q2存每次切了后长度为 p*x 的新蚯蚓,q3存每次切了后长度为 1-p*x 的新蚯蚓。

    因为每次在q1里选最大的切,那么先放入q2,q3的蚯蚓一定比后放入的长度大,即q2,q3是单调的,不需要维护。

    那么只要在最开始对 a[ i ] 排序,q1就也是单调的了。

    每秒钟,在三个队列里选择最大值,切掉,切后放入q2,q3,复杂度为O(m)。

    然后从大到小输出这三个队列里的元素,复杂度O(n+m)。

    总复杂度:O(n+m)。

    100分代码:

    #include<queue>
    #include<cmath>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    #define ll long long
    
    const int maxn=1e5+50;
    const int maxm=7e6+50;
    
    ll n,m,q,u,v,t,a[maxn],len[maxm];
    
    queue<ll>q1,q2,q3;
    int cmp(ll x,ll y){return x>y;}
    
    template<typename T>void read(T& aa){
        char cc; ll ff;aa=0;cc=getchar();ff=1;
        while((cc<'0'||cc>'9')&&cc!='-') cc=getchar();
        if(cc=='-') ff=-1,cc=getchar();
        while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar();
        aa*=ff;
    }
    
    int main(){
        read(n),read(m),read(q),read(u),read(v),read(t);
        for(int i=1;i<=n;i++) read(a[i]);
        sort(a+1,a+1+n,cmp);
        for(int i=1;i<=n;i++) q1.push(a[i]);
        for(int i=1;i<=m;i++){
            ll a1=q1.front()+(i-1)*q,a2=q2.front()+(i-1)*q,a3=q3.front()+(i-1)*q,s1,s2;
            if(q1.empty()) a1=0;
            if(q2.empty()) a2=0;
            if(q3.empty()) a3=0;
            if(a1>=a2&&a1>=a3&&!q1.empty()){
                len[i]=a1;
                q1.pop();s1=a1*u/v,s2=a1-s1;
                s1-=i*q;s2-=i*q;
                q2.push(s1),q3.push(s2);
            }
            else if(a2>=a1&&a2>=a3){
                len[i]=a2;
                q2.pop();s1=a2*u/v,s2=a2-s1;
                s1-=i*q;s2-=i*q;
                q2.push(s1),q3.push(s2);
            }
            else if(a3>=a1&&a3>=a2){
                len[i]=a3;
                q3.pop();s1=a3*u/v,s2=a3-s1;
                s1-=i*q;s2-=i*q;
                q2.push(s1),q3.push(s2);
            }
        }
        for(int i=1;i<=m;i++) if(i%t==0) printf("%d ",len[i]);
        printf("
    ");int tt=0;
        while(!q1.empty()||!q2.empty()||!q3.empty()){
            tt++;
            ll a1=q1.front()+m*q,a2=q2.front()+m*q,a3=q3.front()+m*q;
            if(q1.empty()) a1=0;
            if(q2.empty()) a2=0;
            if(q3.empty()) a3=0;
            if(a1>=a2&&a1>=a3&&!q1.empty()){
                q1.pop();if(tt%t==0) printf("%d ",a1);
            }
            else if(a2>=a1&&a2>=a3&&!q2.empty()){
                q2.pop();if(tt%t==0) printf("%d ",a2);
            }
            else if(a3>=a1&&a3>=a2&&!q3.empty()){
                q3.pop();if(tt%t==0) printf("%d ",a3);
            }
        }
        return 0;
    }
  • 相关阅读:
    设计模式 23
    生活杂谈
    设计模式经典书籍
    ABP 样板开发框架系列
    关键字
    vs 2015
    优秀文章推荐
    Parallel 并行编程
    CSRF
    sql性能优化
  • 原文地址:https://www.cnblogs.com/rlddd/p/9505429.html
Copyright © 2011-2022 走看看