zoukankan      html  css  js  c++  java
  • NOIP提高组2016——蚯蚓

    【题目描述】:
    蚯蚓

    思路:

    我觉得堆的思路还是比较容易看得出来的,毕竟题面描述说每次取最大的,砍成两截在扔进堆里,然后GG ,还是有(80dpts)真水

    #include<cstdio>
    #include<queue>
    #include<cmath>
    #define F(x) floor(1.0*x);
    using namespace std;
    
    int n,m,q,u,v,t;
    
    const int MAXN = 100005;int grow = 0;
    int line1[MAXN],uu=0;int line2[MAXN],vv=0;
    
    struct Node{
        int val,cut;//cut保存的是上一次被切的时候,那么这条蚯蚓的长度就是(grow - x.cut) * q 
        bool operator < ( const Node &a)const{
            return val + (grow - cut) * q < a.val + (grow - a.cut) * q;
        }
    };Node check[MAXN];
    
    priority_queue<Node>Q;
    
    int main(){
        scanf("%d%d%d%d%d%d",&n,&m,&q,&u,&v,&t);
        for(int i=1;i<=n;++i){
            int a;scanf("%d",&a);
            Node aa;aa.val = a;aa.cut = 0;
            Q.push(aa);
        }
        
        double p = 1.0*u/v;
        for(int i=1;i<=m;++i){
            Node x = Q.top() ;Q.pop() ;
            x.val += (grow - x.cut) * q;//当前长度 
            
            if(i % t == 0) line1[++uu] = x.val;
            
            int l = F(p*x.val);int r = x.val - l;
            
            grow++;
            
            Node y;y.val = l;y.cut = i;
            Q.push(y) ;
            
            y.val = r;y.cut = i;
            Q.push(y); 
        }
        
        for(int i=1;i<uu;++i) printf("%d ",line1[i]);
        if(uu ^ 0) printf("%d",line1[uu]);puts("");
        
        for(int i=1;i<=n+m;++i){
            if(i % t == 0){
                Node a = Q.top() ;
                int val = a.val + (grow - a.cut) * q;
                line2[++vv] = val;
            }
            Q.pop() ;
        }
        
        for(int i=1;i<vv;++i) printf("%d ",line2[i]);
        if(vv ^ 0) printf("%d",line2[vv]);
        return 0;
    }
    

    然后思考一下正解,因为堆每次(push)(pop)它自身都要维护一下,这儿就有活生生的(log_n)的复杂度,但转念一想,为什么要维护堆,是为了维护它的单调性,但是单调性。。。。

    我们发现,先把这些蚯蚓按照初始长度排序之后,它们会满足以下性质:

    • 先被切的一定不比后被切的短(包括长的一段和短的一段)
    • 一只蚯蚓被切断后,两部分长度一定不会超过原长度

    那么先把初始长度排序,然后拿三个数组分别存:还没切的蚯蚓,切了后长的一段,切了后短的一段。每次要切的蚯蚓就是三个数组之首的最大值,这样就省掉了(log_n)的复杂度,转而变成的(O(1))

    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<cstring>
    #define F(x) floor(1.0*x)
    using namespace std;
    
    int n,m,q,u,v,t;
    
    const int MAXN = 100005;
    const int MAXM = 7000005;
    
    int a[MAXN];int l[MAXM];//保留长的那段 
    int s[MAXM];//保留短的那段 
    int uu = 0,vv = 0;int ans[MAXN+MAXM];int line1[MAXN],line2[MAXN];
    
    int cuta[MAXN];int cutl[MAXM];
    int cuts[MAXM];
    
    inline bool cmp(int a,int b){
        return a > b;
    }
    
    inline int cutwho(int a,int b,int c){
        if(a >= b && a >= c) return 1;
        if(b >= a && b >= c) return 2;
        if(c >= a && c >= b) return 3;
    }
    
    int main(){
        scanf("%d%d%d%d%d%d",&n,&m,&q,&u,&v,&t);
        for(int i=1;i<=n;++i){
            scanf("%d",&a[i]);
        }
        memset(cuta,0,sizeof cuta);
        double p = 1.0*u/v;
        sort(a+1,a+1+n,cmp);
        
        int ha=1,hl=1,hs=1;
        int ta=n,tl=0,ts=0;
        int grow = 0;
        for(int i=1;i<=m;++i){
            int x = a[ha] + (grow - cuta[ha]) * q;
            int y = l[hl] + (grow - cutl[hl]) * q;
            int z = s[hs] + (grow - cuts[hs]) * q;
            if(ha > ta) x = -1;
            if(hl > tl) y = -1;
            if(hs > ts) z = -1;
            int who = cutwho(x,y,z);
            if(i % t == 0) line1[++uu] = max(max(x , y) , z);
            int ll , rr;
            switch (who){
                case 1:{
                    ll = F(p*x);rr = x - ll;
                    if(ll >= rr) l[++tl] = ll,s[++ts] = rr;
                    else l[++tl] = rr,s[++ts] = ll;
                    cutl[tl] = cuts[ts] = i;
                    ha++;
                    break;
                }
                case 2:{
                    ll = F(p*y);rr = y - ll;
                    if(ll >= rr) l[++tl] = ll,s[++ts] = rr;
                    else l[++tl] = rr,s[++ts] = ll;
                    cutl[tl] = cuts[ts] = i;
                    hl++;
                    break;
                }
                case 3:{
                    ll = F(p*z);rr = z - ll;
                    if(ll >= rr) l[++tl] = ll,s[++ts] = rr;
                    else l[++tl] = rr,s[++ts] = ll;
                    cutl[tl] = cuts[ts] = i;
                    hs++;
                    break;
                }
            }
            grow++;
        }
        int o = 0;
        
        while(ha<=ta || hl<=tl || hs<=ts){
            int x = a[ha] + (grow - cuta[ha]) * q;
            int y = l[hl] + (grow - cutl[hl]) * q;
            int z = s[hs] + (grow - cuts[hs]) * q;
            if(ha > ta) x = -1;
            if(hl > tl) y = -1;
            if(hs > ts) z = -1;
            int who = cutwho(x,y,z);
            ans[++o] = max(max(x , y) , z);
            switch (who){
                case 1:{
                    ha++;
                    break;
                }
                case 2:{
                    hl++;
                    break;
                }
                case 3:{
                    hs++;
                    break;
                }
            }
        }
        
        for(int i=1;i<uu;++i) printf("%d ",line1[i]);
        if(uu) printf("%d",line1[uu]);puts("");
        
        for(int i=t;i<=o;i+=t){
            line2[++vv] = ans[i];
        }
        
        for(int i=1;i<vv;++i) printf("%d ",line2[i]);
        if(vv) printf("%d",line2[vv]);
        return 0;
    }
    
    

    (1316ms),还是挺快。。

  • 相关阅读:
    redis配置引发的问题
    String类的split()方法
    修改mysql编码配置文件不生效
    mysql性能优化小知识点
    limit使用
    mysql执行顺序
    记录一个不知名的错误
    子数组最大和及下标
    maven项目中不能加载java目录下的配置文件
    判断树是否为搜索树
  • 原文地址:https://www.cnblogs.com/lajioj/p/9496772.html
Copyright © 2011-2022 走看看