1. 程式人生 > >[noip2016] 蚯蚓 (隊列)

[noip2016] 蚯蚓 (隊列)

digi amp isdigit max fine cpp n) nlog output

傳送門

Description

技術分享圖片

Input

技術分享圖片

Output

技術分享圖片

Sample Input

樣例1:
3 7 1 1 3 1
3 3 2
樣例2:
3 7 1 1 3 2
3 3 2
樣例3:
3 7 1 1 3 9
3 3 2

Sample Output

樣例1:
3 4 4 4 5 5 6
6 6 6 5 5 4 4 3 2 2
樣例2:
4 4 5
6 5 4 3 2
樣例3:
//空行
2

HINT

技術分享圖片
技術分享圖片

Solution

很顯然是一道優先隊列的題0_0
我們每次拿出最大的一只蚯蚓切割再扔到堆裏(第一問)
然後將堆中的東西依次取出(第二問)
那怎麽將堆中蚯蚓每次加上q呢?
可以設一個變量表示當前蚯蚓已經被加了多少,出隊時加上就行(入隊時記得減去)

那切割後的蚯蚓不增加q怎麽辦?那就入隊時先-q就行了
然後這樣\(O((n+m)log(n+m))\)就應該可以水過很多分了~
然後說正解:其實正解也是跟上面一樣的步驟只不過證明了一個單調性,省去log(n+m)的時間
證明:後分解出的?px?一定小於先分解出的?px? (x-?px?同理)
考慮反證法若\(xi*p+(j-i)*q<=(xj+(j-i)*q)*p\)
則有:\(xi*p+(j-1)*q<=xj*p+(j-i)*q*p\)
因為\(xi>xj\)\(0<p<1\)該式顯然不成立
說明?px?單調遞減成立
有了單調性我們就可以用三個隊列模仿優先隊列一樣操作
時間復雜度:\(O(nlogn+m)\)

Code

//By Menteur_Hxy
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define F(i,a,b) for(register int i=(a);i<=(b);i++)
using namespace std;

int read() {
    int x=0,f=1; char c=getchar();
    while(!isdigit(c)) {if(c=='-')f=-f;c=getchar();}
    while(isdigit(c)) x=(x<<1)+(x<<3)+c-48,c=getchar();
    return x*f;
}

const int INF=0x7fffffff;
const int N=1e5+10,M=7e6+10;
int n,m,q,u,v,t,reg;
int Q[3][M],qt[3],qf[3];

bool cmp(int x,int y) {return x>y;}

int Max() {
    int res=-INF,cnt;
    F(i,0,2) if(qf[i]<qt[i]&&res<Q[i][qf[i]+1]) 
        res=Q[i][qf[i]+1],cnt=i;
    qf[cnt]++; return res;
}

int main() {
    n=read(),m=read(),q=read(),u=read(),v=read(),t=read();
    F(i,1,n) Q[0][++qt[0]]=read();
    sort(Q[0]+1,Q[0]+qt[0]+1,cmp);
    F(i,1,m) {
        int x=Max()+reg;
        if(i%t==0) printf("%d ",x);
        int l=(long long)x*u/v,r=x-l;
        Q[1][++qt[1]]=l-reg-q;
        Q[2][++qt[2]]=r-reg-q;
        reg+=q;
    }
    putchar('\n');
    F(i,1,n+m) {
        int x=Max()+reg;
        if(i%t==0) printf("%d ",x);
    }
    return 0;
}

[noip2016] 蚯蚓 (隊列)