1. 程式人生 > >洛谷 P2827 蚯蚓 解題報告

洛谷 P2827 蚯蚓 解題報告

洪荒之力 strong pri 符號 理解 .com image ++ can

P2827 蚯蚓

題目描述

本題中,我們將用符號 \(\lfloor c \rfloor\) 表示對 \(c\) 向下取整,例如:\(\lfloor 3.0 \rfloor = \lfloor 3.1 \rfloor = \lfloor 3.9 \rfloor = 3\)

蛐蛐國最近蚯蚓成災了!隔壁跳蚤國的跳蚤也拿蚯蚓們沒辦法,蛐蛐國王只好去請神刀手來幫他們消滅蚯蚓。

蛐蛐國裏現在共有 \(n\) 只蚯蚓(\(n\) 為正整數)。每只蚯蚓擁有長度,我們設第 \(i\) 只蚯蚓的長度為 \(a_i\)(\(i=1,2,\dots,n\)),並保證所有的長度都是非負整數(即:可能存在長度為 \(0\)

的蚯蚓)。

每一秒,神刀手會在所有的蚯蚓中,準確地找到最長的那一只(如有多個則任選一個)將其切成兩半。神刀手切開蚯蚓的位置由常數 \(p\)(是滿足 \(0 < p < 1\) 的有理數)決定,設這只蚯蚓長度為 \(x\),神刀手會將其切成兩只長度分別為 \(\lfloor px \rfloor\)\(x - \lfloor px \rfloor\) 的蚯蚓。特殊地,如果這兩個數的其中一個等於 \(0\),則這個長度為 \(0\) 的蚯蚓也會被保留。此外,除了剛剛產生的兩只新蚯蚓,其余蚯蚓的長度都會增加 \(q\)(是一個非負整常數)。

蛐蛐國王知道這樣不是長久之計,因為蚯蚓不僅會越來越多,還會越來越長。蛐蛐國王決定求助於一位有著洪荒之力的神秘人物,但是救兵還需要 \(m\)

秒才能到來……(\(m\) 為非負整數)

蛐蛐國王希望知道這 \(m\) 秒內的戰況。具體來說,他希望知道:

\(m\) 秒內,每一秒被切斷的蚯蚓被切斷前的長度(有 \(m\) 個數);
\(m\) 秒後,所有蚯蚓的長度(有 \(n + m\) 個數)。
蛐蛐國王當然知道怎麽做啦!但是他想考考你……

輸入輸出格式

輸入格式:

第一行包含六個整數 \(n,m,q,u,v,t\),其中:\(n,m,q\) 的意義見【問題描述】;\(u,v,t\) 均為正整數;你需要自己計算 \(p=u / v\)(保證 \(0 < u < v\));\(t\) 是輸出參數,其含義將會在【輸出格式】中解釋。

第二行包含 nn 個非負整數,為 \(a_1, a_2, \dots, a_n\),即初始時 \(n\) 只蚯蚓的長度。

同一行中相鄰的兩個數之間,恰好用一個空格隔開。

保證 \(1 \leq n \leq 10^5\)\(0 \leq m \leq 7 \times 10^6\)\(0 < u < v \leq 10^9\)\(0 \leq q \leq 200\)\(1 \leq t \leq 71\)\(0 \leq a_i \leq 10^8\)

輸出格式:

第一行輸出 \(\left \lfloor \frac{m}{t} \right \rfloor\)個整數,按時間順序,依次輸出第 \(t\) 秒,第 \(2t\) 秒,第 \(3t\) 秒,……被切斷蚯蚓(在被切斷前)的長度。

第二行輸出 \(\left \lfloor \frac{n+m}{t} \right \rfloor\)個整數,輸出 \(m\) 秒後蚯蚓的長度;需要按從大到小的順序,依次輸出排名第 \(t\),第 \(2t\),第 \(3t\),……的長度。

同一行中相鄰的兩個數之間,恰好用一個空格隔開。即使某一行沒有任何數需要輸出,你也應輸出一個空行。

請閱讀樣例來更好地理解這個格式。

說明:

技術分享圖片


堆的做法很顯然,大概有65~80pts,算是送了很多分了

一看輸出都強行怕你T,那一定是\(O(n)\)

記得合並果子有一個雙隊列\(O(n)\)做法嗎?

事實上跟這個題差不多噠

我們開三個隊列,一個存放原來的蚯蚓,一個存放被這樣切\(\lfloor px \rfloor\)的蚯蚓,另一個存放被\(x - \lfloor px \rfloorx\)這樣切的

註意到在後兩個隊列中先拿出來的一定比後拿出來的要長,具有單調性

對於第一個隊列我們可以先排序,然後每次取三個隊列中隊尾最大的,切開放到相應的隊頭

增加的量我們可以維護一個被切斷的時間點

註意中間過程可能會爆int


Code:

#include <cstdio>
#include <algorithm>
#define ll long long
const int N=8e6;
ll q1[N][2],q2[N][2],q3[N][2],l1=1,l2=1,l3=1,r1,r2,r3;
ll n,m,q,u,v,t,a[N];//n個m刀增q p=u/v t輸出
int main()
{
    scanf("%lld%lld%lld%lld%lld%lld",&n,&m,&q,&u,&v,&t);
    for(int i=1;i<=n;++i)
        scanf("%lld",a+i);
    r1=n;
    std::sort(a+1,a+1+n);
    for(int i=1;i<=n;i++) q1[n+1-i][0]=a[i];
    for(register ll mx,id,i=1;i<=m;++i)
    {
        mx=0;
        if(l1<=r1&&mx<q1[l1][0]+(i-q1[l1][1]-1)*q) mx=q1[l1][0]+(i-q1[l1][1]-1)*q,id=1;
        if(l2<=r2&&mx<q2[l2][0]+(i-q2[l2][1]-1)*q) mx=q2[l2][0]+(i-q2[l2][1]-1)*q,id=2;
        if(l3<=r3&&mx<q3[l3][0]+(i-q3[l3][1]-1)*q) mx=q3[l3][0]+(i-q3[l3][1]-1)*q,id=3;
        if(i%t==0) printf("%lld ",mx);
        if(id==1) ++l1;if(id==2) ++l2;if(id==3) ++l3;
        q2[++r2][0]=mx*u/v,q2[r2][1]=i;
        q3[++r3][0]=mx-mx*u/v,q3[r3][1]=i;
    }
    printf("\n");ll i=0;
    while(l1<=r1||l2<=r2||l3<=r3)
    {
        ll id,mx=0;++i;
        if(l1<=r1&&mx<q1[l1][0]+(m-q1[l1][1])*q) mx=q1[l1][0]+(m-q1[l1][1])*q,id=1;
        if(l2<=r2&&mx<q2[l2][0]+(m-q2[l2][1])*q) mx=q2[l2][0]+(m-q2[l2][1])*q,id=2;
        if(l3<=r3&&mx<q3[l3][0]+(m-q3[l3][1])*q) mx=q3[l3][0]+(m-q3[l3][1])*q,id=3;
        if(i%t==0) printf("%lld ",mx);
        if(id==1) ++l1;if(id==2) ++l2;if(id==3) ++l3;
    }
    printf("\n");
    return 0;
}

2018.9.1

洛谷 P2827 蚯蚓 解題報告