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\),还是挺快。。

猜你喜欢

转载自www.cnblogs.com/lajioj/p/9496772.html