zoukankan      html  css  js  c++  java
  • [NOIP2016]蚯蚓 题解

    题目描述

    本题中,我们将用符号[c]表示对c向下取整,例如:[3.0」= [3.1」= [3.9」=3。
    蛐蛐国最近蚯蚓成灾了!隔壁跳蚤国的跳蚤也拿蚯蚓们没办法,蛐蛐国王只好去请神刀手来帮他们消灭蚯蚓。
    蛐蛐国里现在共有n只蚯蚓(n为正整数)。每只蚯蚓拥有长度,我们设第i只蚯蚓的长度为a_i(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个非负整数,为ai,a2,…,an,即初始时n只蚯蚓的长度。
    同一行中相邻的两个数之间,恰好用一个空格隔开。
    保证1<=n<=10^5,0< m<7*10^6,0< u< v<10^9,0<=q<=200,1< t<71,0< ai<10^8。

    输出格式

    第一行输出[m/t]个整数,按时间顺序,依次输出第t秒,第2t秒,第3t秒……被切断蚯蚓(在被切断前)的长度。
    第二行输出[(n+m)/t]个整数,输出m秒后蚯蚓的长度;需要按从大到小的顺序,依次输出排名第t,第2t,第3t……的长度。
    同一行中相邻的两个数之间,恰好用一个空格隔开。即使某一行没有任何数需要 输出,你也应输出一个空行。
    请阅读样例来更好地理解这个格式。

    样例输入

    3 7 1 1 3 1
    3 3 2

    样例输出

    3 4 4 4 5 5 6
    6 6 6 5 5 4 4 3 2 2  

    $Solution:$

    暴力很好打吧,直接开一个堆维护大小关系,再用一个变量当加法标记就好了。

    注意为了防止炸精要直接用分数乘,记得开long long。

    得分:玄学

    $loj$评测结果:

    STL优先队列:85pts

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<queue>
    using namespace std;
    int read()
    {
        int x=0,f=1;char ch=getchar();
        while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
        while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
        return x*f;
    }
    const int N=1e5+5;
    typedef long long ll;
    int n,m,g,u,v,t;
    int inc,a[N];
    priority_queue<int> q;
    int main()
    {
        n=read();m=read();g=read();u=read();v=read();t=read();
        for(int i=1;i<=n;i++)
            a[i]=read(),q.push(a[i]);
        for(int now=1;now<=m;now++)
        {
            int x=q.top()+inc;q.pop();
            if(now%t==0)printf("%d ",x);
            //cout<<now<<' '<<x<<endl;
            int len1=(1LL*x*u)/v,len2=x-len1;
            len1-=g+inc;len2-=g+inc;
            q.push(len1);q.push(len2);
            inc+=g;
        }
        putchar('
    ');
        int sz=q.size();
        for(int i=1;i<=sz;i++)
        {
            int x=q.top()+inc;q.pop();
            if(i%t==0)printf("%d ",x);
        }
        putchar('
    ');
        return 0;
    }
    

    平板电视配对堆:80pts

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<ext/pb_ds/priority_queue.hpp>
    using namespace __gnu_pbds;
    using namespace std;
    int read()
    {
        int x=0,f=1;char ch=getchar();
        while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
        while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
        return x*f;
    }
    const int N=1e5+5,M=8e6+5;
    typedef long long ll;
    int n,m,g,u,v,t;
    int inc,a[N];
    __gnu_pbds::priority_queue<int, less<int>, pairing_heap_tag> q;
    int main()
    {
        n=read();m=read();g=read();u=read();v=read();t=read();
        for(int i=1;i<=n;i++)
            a[i]=read(),q.push(a[i]);
        for(int now=1;now<=m;now++)
        {
            int x=q.top()+inc;q.pop();
            if(now%t==0)printf("%d ",x);
            int len1=(1LL*x*u)/v,len2=x-len1;
            len1-=g+inc;len2-=g+inc;
            q.push(len1);q.push(len2);
            inc+=g;
        }
        putchar('
    ');
        int sz=q.size();
        for(int i=1;i<=sz;i++)
        {
            int x=q.top()+inc;q.pop();
            if(i%t==0)printf("%d ",x);
        }
        putchar('
    ');
        return 0;
    }
    

    垃圾博主手写的可能是假的配对堆:65pts

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #define re register
    //#include<queue>
    using namespace std;
    int read()
    {
        int x=0,f=1;char ch=getchar();
        while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
        while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
        return x*f;
    }
    const int N=1e5+5,M=8e6+5;
    typedef long long ll;
    int n,m,g,u,v,t;
    int inc,a[N];
    //priority_queue<int> q;
    struct stack
    {
        int s[M];
        int tp,cnt;
        inline int top()
        {
            if(!tp)return ++cnt;
            return s[tp--];
        }
        inline void push(int x){s[++tp]=x;}
    }node,edge;
    struct Pairheap
    {
        int root,fa[M],val[M];
        int sz;
        int head[M],to[M],nxt[M],que[M];
        inline void add(int x,int y)
        {
            int tot=edge.top();
            to[tot]=y;
            nxt[tot]=head[x];
            head[x]=tot;
        }
        inline int merge(int x,int y)
        {
            if(val[x]<val[y])swap(x,y);
            add(x,y);fa[y]=x;
            return x;
        }
        inline void push(int Val)
        {
            ++sz;
            int x=node.top();
            val[x]=Val;
            root=root?merge(root,x):x;
        }
        inline int top()
        {
            return val[root];
        }
        inline void pop()
        {
            --sz;
            re int l=0,r=0;
            for(re int i=head[root];i;i=nxt[i])
            {
                int y=to[i];
                edge.push(i);
                if(fa[y]==root)fa[y]=0,que[++r]=y;
            }
            node.push(root);
            head[root]=fa[root]=0;
            val[root]=0;root=0;
            while(l<r)
            {
                ++l;if(l==r){root=que[l];return ;}
                int x=que[l],y=que[++l];
                que[++r]=merge(x,y);
            }
        }
        inline int size(){return sz;}
    }q;
    
    int main()
    {
        n=read();m=read();g=read();u=read();v=read();t=read();
        for(int i=1;i<=n;i++)
            a[i]=read(),q.push(a[i]);
        for(int now=1;now<=m;now++)
        {
            int x=q.top()+inc;q.pop();
            if(now%t==0)printf("%d ",x);
            int len1=(1LL*x*u)/v,len2=x-len1;
            len1-=g+inc;len2-=g+inc;
            q.push(len1);q.push(len2);
            inc+=g;
        }
        putchar('
    ');
        int sz=q.size();
        for(int i=1;i<=sz;i++)
        {
            int x=q.top()+inc;q.pop();
            if(i%t==0)printf("%d ",x);
        }
        putchar('
    ');
        return 0;
    }
    

    基本和预期结果完全相反QAQ

    然后仔细观察一下这个暴力,你会发现一个比较显然的性质:堆内元素有单调性。

    因为你用了加法标记,而每次取出后都会先拆成两段再分别-q之后才放回去,所以元素应该是单调减的。

    这种题的套路一般是开多个队列然后比较队首,那么对于本题只需要开三个队列,每次取出最大的队首就好了。

    第一个队列存放初始值,每次得到最大队首后拆开,$lfloor px floor$放回第二个队列,$x-  lfloor  px  floor$放回第三个即可。

    为了保证开始的单调性,别忘了sort一下。

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<queue>
    #include<algorithm>
    using namespace std;
    int read()
    {
        int x=0,f=1;char ch=getchar();
        while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
        while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
        return x*f;
    }
    const int N=1e5+5,inf=0x3f3f3f3f;
    typedef long long ll;
    int n,m,g,u,v,t;
    int inc,a[N];
    queue<int> q1,q2,q3;
    int main()
    {
        n=read();m=read();g=read();u=read();v=read();t=read();
        for(int i=1;i<=n;i++)
            a[i]=read();
        sort(a+1,a+n+1,greater<int>());
        for(int i=1;i<=n;i++)
            q1.push(a[i]);
        for(int now=1;now<=m;now++)
        {
            int x=-inf;
            if(!q1.empty())x=max(x,q1.front());
            if(!q2.empty())x=max(q2.front(),x);
            if(!q3.empty())x=max(x,q3.front());
            if(!q1.empty()&&x==q1.front())q1.pop();
            else if(!q2.empty()&&x==q2.front())q2.pop();
            else if(!q3.empty()&&x==q3.front())q3.pop();
            x+=inc;
            if(now%t==0)printf("%d ",x);
            //cout<<now<<' '<<x<<endl;
            int len1=(1LL*x*u)/v,len2=x-len1;
            len1-=g+inc;len2-=g+inc;
            q2.push(len1);q3.push(len2);
            inc+=g;
        }
        putchar('
    ');
        for(int i=1;i<=n+m;i++)
        {
            int x=-inf;
            if(!q1.empty())x=max(x,q1.front());
            if(!q2.empty())x=max(q2.front(),x);
            if(!q3.empty())x=max(x,q3.front());
            if(i%t==0)printf("%d ",x+inc);
            if(!q1.empty()&&x==q1.front())q1.pop();
            else if(!q2.empty()&&x==q2.front())q2.pop();
            else if(!q3.empty()&&x==q3.front())q3.pop();
    
        }
        putchar('
    ');
        return 0;
    }
    
  • 相关阅读:
    高阶LOOP
    C 语言常用方法技巧
    Linux内存压力测试memtester工具
    Matrix computations in C
    代码整洁之道语句摘录
    Ubuntu Mysql 常用指令
    linux 汇编 函数调用
    技术有待改进,知识需要更新
    原来那些网络协议都是这么回事啊!!!
    谢谢老乡们的关注……
  • 原文地址:https://www.cnblogs.com/Rorschach-XR/p/11799622.html
Copyright © 2011-2022 走看看