【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("\n");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;
}

 

posted @ 2018-08-20 14:45  rld  阅读(155)  评论(0编辑  收藏  举报