[队列]【NOIP2016D2T2】蚯蚓 题解

传送门:
洛谷
UOJ

解题报告

取最小值就直接想到堆,但是注意m为 7106 ,也就是最后可能会有 107 以上的个数,堆的 O(nlogn) 显然会TLE,所以需要更优的方案。

首先会发现蚯蚓的增长是很麻烦的,但是这是相对的。所以可以直接让被选出的蚯蚓减少长度而不是让其他蚯蚓增加长度。也就是说所有的蚯蚓其实都是”最初的长度”,然后要切的时候加回原长,切完后的两段又捡回”初始长度”。

然后再思考,每次切完蚯蚓后,两段的长度都不会比原串长。所以其实蚯蚓的“原长”(注意是原长,不是现在的长度,看样例就知道)是递减的,然后,就可以直接开3个队列分别处理0:原长,1:一段和2:另一段。每次3个队列头中找最长的,然后分成两端,分别放在1,2队列后面。

然后注意,因为捡回原长后有可能是负的,也有可能负的太大了。所以需要在找出最大值的时候把初始的负值越小越好, 109 会被洛谷卡掉,UOJ hack掉,所以直接 (2311) 。查了两天代码的惨痛教训。

复杂度:
时间: O(m)
空间: O(3m)

#include
#include
#define LL long long
#define INF (((1<<30)-1)<<1)+1
using namespace std;
int n,m,p,q,t,u,now,que[3][7000005],hed[3],til[3];
inline char nc(){
    static char buf[100000],*pa=buf,*pb=buf;
    return pa==pb&&(pb=(pa=buf)+fread(buf,1,100000,stdin),pa==pb)?EOF:*pa++;
}
inline void readi(int &x){
    x=0; char ch=nc();
    while ('0'>ch||ch>'9') ch=nc();
    while ('0'<=ch&&ch<='9') {x=x*10+ch-'0'; ch=nc();}
}
inline bool cmp(const int x,const int y){return x>y;}
void _init(){
    freopen("earthworm.in","r",stdin);
    freopen("earthworm.out","w",stdout);
    readi(n); readi(m); readi(u); readi(p); readi(q); readi(t);
    for (int i=1;i<=n;i++) readi(que[0][i]); sort(que[0]+1,que[0]+n+1,cmp);
}
inline int geti(){
    int tem=-INF,ans;
    for (int i=0;i<3;i++) if (hed[i]<=til[i]&&que[i][hed[i]]>tem) {tem=que[i][hed[i]]; ans=i;}
    return ans;
}
void _solve(){
    hed[0]=hed[1]=hed[2]=1; til[1]=til[2]=now=0; til[0]=n;
    for (int i=1,ti=t;i<=m;i++,now+=u){
        int x=geti(),y=que[x][hed[x]++]+now; if (i==ti) {printf("%d ",y); ti+=t;}
        int L=(LL)y*p/q,R=y-L; que[1][++til[1]]=L-now-u; que[2][++til[2]]=R-now-u;
    }
    printf("\n");
    for (int i=1,ti=t;i<=n+m;i++){
        int x=geti(),y=que[x][hed[x]++]+now; if (i==ti){ti+=t; printf("%d ",y);}
    }
}
int main()
{
    _init();
    _solve();
    return 0;
}

你可能感兴趣的:(NOIP题解,单调队列&单调栈)