1. 程式人生 > >[NOIp2016] 蚯蚓

[NOIp2016] 蚯蚓

隊列 tmp 負數 p s turn == 不用 由於 取整

類型:單調隊列

傳送門:>Here<

題意:有$N$只蚯蚓,每秒都會伸長$q$。每一次都會有人選出最長的一條切成兩半,長度分別是$\left \lfloor px \right \rfloor$和$x - \left \lfloor px \right \rfloor$ 詢問每一秒最長的蚯蚓被切前的長度,以及$m$秒後每條蚯蚓的長度(從大到小排序)

解題思路

NOIp的subtask還是非常良心的。於是決定不看題解開始幹……

看完題目,花了10分鐘打了一個超級暴力模擬,35分get 然後發現有60分是$q=0$的情況……這不是就是一個裸的堆嗎?打了15分鐘,50分get(為什麽只有50……)

然後想了很久沒思路,瞟了一眼題解一眼就看到去減長度而不用管加,趕緊開始打調試近40分鐘後85分get 然後就開始看題解打正解了……正解也調了20分鐘作用 最終的AC代碼再交一次竟然變成了90 又交一次變成了95 再交一次又100了……洛谷的評測機也不是很穩定啊,這題還是有點卡常

先來看看85分怎麽拿。85分的寫法在思想上還是很重要的——蚯蚓每秒增長$q$,可以看做是被切的蚯蚓減去$q$。因此我們可以維護一個堆,這樣堆的內部就不需要反復更新。但是細節要註意,選擇切割的蚯蚓長度應該拿真實的長度來算

然後來看正解。很容易發現,對於兩條蚯蚓$x,y$,如果$x>y$,則$x$肯定會先被切掉。不妨設$x$被切掉以後變為$\{a_1, b_1\}$,$y$被切後變為$\{a_2, b_2\}$

由於$y$肯定在$x$被切後若幹秒被切,不妨設為$t$秒,則那時四條分出來的小蚯蚓的長度是可以表示的。我們希望能夠證明到那時$a_1 > a_2, b_1 > b_2$。我們先來證明$a_1>a_2$,$b$也類似$$a_1 = a_1 + q*t =\left \lfloor px \right \rfloor + q*t$$$$a_2 = \left \lfloor p(y+q*t) \right \rfloor$$則$$a_1-a_2=\left \lfloor px \right \rfloor + q*t-\left \lfloor p(y+q*t) \right \rfloor$$去掉向下取整符號並不會影響答案,因此$$a_1-a_2=p*x+q*t-p*y-p*q*t$$整理得$$a_1-a_2=p(x-y)+q*t(1-p)>0$$故$$a_1>a_2$$

因此我們得出結論:一條蚯蚓如果比另一條蚯蚓早被切,那麽它分出來的兩條蚯蚓也永遠比後分出來的兩條蚯蚓要長

於是我們可以考慮維護三個隊列$q_1,q_2,q_3$,$q_1$中儲存沒被切過的蚯蚓,$q_2$中儲存切出來的左半條,$q_3$表示右半條。要求隊列單調不上升,每一次取出三個隊列的隊頭中的最大值即為所有蚯蚓中最長的,切成兩半後分別塞到$q_2,q_3$的隊尾。由於剛才證明了後切的一定要短,所以插入隊尾後單調性依然滿足。故這樣的做法是正確的

Code

cur=-INF而不能是-1,因為負數有可能減到很大

/*By DennyQi 2018.8.15*/
#include <cstdio>
#include <queue>
#include <cstring>
#include <algorithm>
#define  r  read()
#define  Max(a,b)  (((a)>(b)) ? (a) : (b))
#define  Min(a,b)  (((a)<(b)) ? (a) : (b))
using namespace std;
typedef long long ll;
const int MAXN = 7000010;
const int MAXM = 27010;
const int INF = 1061109567;
inline int read(){
    int x = 0; int w = 1; register int c = getchar();
    while(c ^ - && (c < 0 || c > 9)) c = getchar();
    if(c == -) w = -1, c = getchar();
    while(c >= 0 && c <= 9) x = (x << 3) + (x << 1) + c - 0, c = getchar(); return x * w;
}
double p;
int N,M,Q,U,V,T,_mx,pos,tmp,x,y,cur,top;
int q[4][MAXN],h[4],t[4],a[MAXN];
inline bool comp(const int& a, const int& b){ return a>b; }
int main(){
    N=r,M=r,Q=r,U=r,V=r,T=r;
    p = (double)(U) / (double)(V);
    for(int i = 1; i <= N; ++i) a[i] = r;
    h[1] = h[2] = h[3] = 1;
    q[2][1] = q[3][1] = -INF;
    sort(a+1,a+N+1,comp);
    for(int i = 1; i <= N; ++i) q[1][++t[1]] = a[i];
    for(int _t = 1; _t <= M; ++_t){
        cur = -INF;
        for(int i = 1; i <= 3; ++i){
            if(h[i] > t[i]) continue;
            if(q[i][h[i]] > cur){ cur = q[i][h[i]]; pos = i; }    
        }
        if(_t % T == 0) printf("%d ", cur+(_t-1)*Q);
        ++h[pos];
        x = (cur+(_t-1)*Q) * p, y = (cur+(_t-1)*Q) - x;
        q[2][++t[2]] = x-_t*Q, q[3][++t[3]] = y-_t*Q;
    }
    puts("");
    for(int i = 1; i <= 3; ++i)
        for(int j = h[i]; j <= t[i]; ++j) a[++top] = q[i][j];
    sort(a+1,a+top+1,comp);
    for(int i = 1; i <= top; ++i)
        if(i % T == 0) printf("%d ", a[i]+M*Q);
    return 0;
}

[NOIp2016] 蚯蚓