UOJ264 【NOIP2016】蚯蚓


本文版權歸ljh2000和博客園共有,歡迎轉載,但須保留此聲明,並給出原文鏈接,謝謝合作。

 

 

本文作者:ljh2000
作者博客:http://www.cnblogs.com/ljh2000-jump/
轉載請注明出處,侵權必究,保留最終解釋權!

 

 

Description

本題中,我們將用符號[c]表示對c向下取整,例如:[3.0」= [3.1」=[3.9」=3。蛐蛐國最近蚯蚓成災了!隔壁跳
蚤國的跳蚤也拿蚯蚓們沒辦法,蛐蛐國王只好去請神刀手來幫他們消滅蚯蚓。蛐蛐國里現在共有n只蚯蚓(n為正整
數)。每只蚯蚓擁有長度,我們設第i只蚯蚓的長度為a_i(i=1,2,...,n),並保證所有的長度都是非負整數(即:可
能存在長度為0的蚯蚓)。每一秒,神刀手會在所有的蚯蚓中,准確地找到最長的那一只(如有多個則任選一個)
將其切成兩半。神刀手切開蚯蚓的位置由常數p(是滿足0<p<1的有理數)決定,設這只蚯蚓長度為x,神刀手會將其
切成兩只長度分別為[px]和x-[px]的蚯蚓。特殊地,如果這兩個數的其中一個等於0,則這個長度為0的蚯蚓也會被
保留。此外,除了剛剛產生的兩只新蚯蚓,其余蚯蚓的長度都會增加q(是一個非負整常數)。蛐蛐國王知道這樣不
是長久之計,因為蚯蚓不僅會越來越多,還會越來越長。蛐蛐國王決定求助於一位有着洪荒之力的神秘人物,但是
救兵還需要m秒才能到來......(m為非負整數)蛐蛐國王希望知道這m秒內的戰況。具體來說,他希望知道:?m秒內
,每一秒被切斷的蚯蚓被切斷前的長度(有m個數)?m秒后,所有蚯蚓的長度(有n+m個數)。蛐蛐國王當然知道怎
么做啦!但是他想考考你......
 

Input

第一行包含六個整數n,m,q,u,v,t,其中:n,m,q的意義見問題描述;
u,v,t均為正整數;你需要自己計算p=u/v(保證0<u<v)t是輸出參數,其含義將會在輸出格式中解釋。
第二行包含n個非負整數,為ai,a2,...,an,即初始時n只蚯蚓的長度。
同一行中相鄰的兩個數之間,恰好用一個空格隔開。
保證1<=n<=10^5,0<m<7*10^6,0<u<v<10^9,0<=q<=200,1<t<71,0<ai<10^8。
 

Output

第一行輸出[m/t]個整數,按時間順序,依次輸出第t秒,第2t秒,第3t秒……被切斷蚯蚓(在被切斷前)的長度。
第二行輸出[(n+m)/t]個整數,輸出m秒后蚯蚓的長度;需要按從大到小的順序
依次輸出排名第t,第2t,第3t……的長度。
同一行中相鄰的兩個數之間,恰好用一個空格隔開。即使某一行沒有任何數需要 輸出,你也應輸出一個空行。
請閱讀樣例來更好地理解這個格式。
 

Sample Input

3 7 1 1 3 1
3 3 2

Sample Output

3 4 4 4 5 5 6
6 6 6 5 5 4 4 3 2 2
 
 
 
正解:單調隊列
解題報告:
 
60分

      考慮每次取出一個最大值這個操作,堆來維護比較方便,但是每次加上一個q似乎不好處理。我們考慮增加一個全局變量tag,表示每個數都需要加上tag,這樣就可以避免對於堆中所有元素增加,而只需把每次新的兩個元素減去q,再放入堆中即可。具體做法:系統堆維護,每次取出最大元素,然后加上tag,得到真實值,算出兩個新元素值,tag加上q,兩個新元素值減去tag,丟入堆中。

 

65分

      系統堆常數太大了,加上CCF的評測機的速度有限,30w的點剛好被卡T。換成手寫堆即可通過第18個測試點。

 

90分

      注意到q=0同樣有很多的部分分,如果我們能解決掉q=0的情況,再加上上述算法,即可獲得90分。

      首先q=0表示每次沒有自增操作,很容易發現其實所有的元素都是在單調下降(或者說不增)的,也就是說每次取出來的最大元素肯定是不增的,這就說明切掉之后分成的兩個新元素,一定比之前任何一次切掉之后的新元素要小。

     這啟示我們,似乎在q=0的時候具有單調性。我們維護三個隊列q1、q2、q3。初始時q1是從大到小排列的n個數,q2,q3為空。每次操作,取出三個隊列的隊首元素中最大的那個,設為x,把px丟到q1中,x-px丟到q2中。根據我們上面所說的,我們可以保證任何時候取出來的都是不增的,所以我們可以保證這三個隊列在任何時候都是單調不增的。這樣就可以通過90%的測試點了。

 

100分

      通過對於q=0時單調性的研究,我們可以發現其實q≠0的時候同樣具備單調性。

      我們對於q≠0的時候,假設不滿足單調性,即存在之前的某次分割的為a,中間間隔了N輪之后,這次分割的元素在a分割時它為b,則此時為b+N*q,並且b切出來的部分比之前a切出來的要長。假設上述情況存在,則說明滿足:

  $${a*p+N*q<(b+N*q)*p(只考慮乘以p的部分)}$$

  因為a>=b,而右邊展開之后就變成了$${b*p+N*q*p}$$因為p<1,而a>=b,顯然上式不成立。可以通過反證法說明這一點。

  從單調性的角度也可以證明算法的正確性:因為我們每次取出一個元素x,分成兩部分,然后把整體加上q,再把這兩個新元素-q。是不是意味着在隊列中保存的元素的值仍然是單調遞減的(因為沒有任何加法操作,只會因為被分成兩半而變小)?也就是說,不管怎么變,這個全局的增量tag是不會影響相對大小的,因為tag的針對對象是全體元素,所以如果在減掉tag的情況下滿足的大小關系加上tag后顯然滿足,因為同時加上一個數,相對大小並不會改變。所以我們可以發現,在q≠0的時候,隊列中的元素同樣滿足單調性,套用上述算法即可獲得滿分。

 

 

注意事項

  由於題目中不是直接給出的p,而是通過給出分子分母要求我們自己計算p,來降低精度誤差。在乘的時候需要開一個long long的臨時變量,除完之后再轉成int就可以了。其余的均可只開int。

 
 
 
 1 //It is made by ljh2000
 2 #include <iostream>
 3 #include <cstdlib>
 4 #include <cstring>
 5 #include <cstdio>
 6 #include <cmath>
 7 #include <algorithm>
 8 #include <ctime>
 9 #include <vector>
10 #include <queue>
11 #include <map>
12 #include <set>
13 #include <string>
14 using namespace std;
15 typedef long long LL;
16 const int MAXN = 7000011; 
17 const LL inf = (1LL<<60);
18 int n,m,q,t,tag,Q[3][MAXN],head[3],tail[3];
19 LL u,v;
20 
21 inline int getint(){
22     int w=0,q=0; char c=getchar(); while((c<'0'||c>'9') && c!='-') c=getchar();
23     if(c=='-') q=1,c=getchar(); while (c>='0'&&c<='9') w=w*10+c-'0',c=getchar(); return q?-w:w;
24 }
25 inline bool cmp(int q,int qq){return q>qq;}
26 inline void work(){
27     n=getint(); m=getint(); q=getint(); u=getint(); v=getint(); t=getint(); int ljh1,ljh2,from; LL now; int out=0;
28     for(int i=1;i<=n;i++) Q[0][i]=getint(); sort(Q[0]+1,Q[0]+n+1,cmp); tag=0; head[0]=head[1]=head[2]=1; tail[0]=n; tail[1]=tail[2]=0;
29     for(int i=1;i<=m;i++) {
30         now=-inf; from=-1; for(int j=0;j<3;j++) if(head[j]<=tail[j]) { if(Q[j][head[j]]>now) { now=Q[j][head[j]]; from=j; } }
31         now+=tag; out++; if(out==t) { printf("%lld ",now); out=0; }
32         ljh1=now*u/v; ljh2=now-ljh1; head[from]++;  tag+=q;
33         ljh1-=tag; ljh2-=tag;
34         Q[1][++tail[1]]=ljh1; Q[2][++tail[2]]=ljh2;    
35     }
36     printf("\n"); m+=n; out=0;
37     for(int i=1;i<=m;i++) {
38         now=-inf; from=-1; for(int j=0;j<3;j++) if(head[j]<=tail[j]) { if(Q[j][head[j]]>now) { now=Q[j][head[j]]; from=j; } }
39         now+=tag; out++; if(out==t) { printf("%lld ",now); out=0; }
40         head[from]++;
41     }
42 }
43 
44 int main()
45 {
46     work();
47     return 0;
48 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM