本文版權歸ljh2000和博客園共有,歡迎轉載,但須保留此聲明,並給出原文鏈接,謝謝合作。
本文作者:ljh2000
作者博客:http://www.cnblogs.com/ljh2000-jump/
轉載請注明出處,侵權必究,保留最終解釋權!
Description
Input
Output
Sample Input
3 3 2
Sample Output
6 6 6 5 5 4 4 3 2 2
考慮每次取出一個最大值這個操作,堆來維護比較方便,但是每次加上一個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 }
