題目鏈結
原創鏈結
首先來看題(沒看題的看題去!),題面應該不難理解,就是每次相鄰分數的兩個人根據實力值進行比較,然後輸贏分治,不斷排序罷了。
「肯定要sort哇!每次更新分數,然後sort不就得了?」
其實本質上來說,是可以的,但是sort會**——時間會**。但是無論時間怎樣,那都是ccf的測試點有沒有卡tle的問題而已。但如果真從程式設計本身**,sort無疑是乙個很浪費的演算法。
一、關於sort的浪費
首先讓我們想想,sort其實就是快速排序,而快速排序其實就是二分的思想(胡亂在中間立flag)。穩定的話o(nlogn)左右。但是仔細想想此題——每次需要更新的值,都是相鄰兩個人變化後的分數;而相鄰的分數,有些是不會改變位置的,而快速排序則是每次全部修改,必然會造成浪費。
二、關於歸併排序
然後考慮歸併排序: 歸併排序的思想就是合併兩個同序陣列的線性方式——每次比較兩個有序陣列指標指向的值,誰更小(大)則放到temp陣列裡,然後刪掉進入temp的元素,指標++。
於是歸併排序的**就不難理解了:
void merge(int l,int r)
while(i<=mid)temp[++p]=a[++i];
while(j<=r)temp[++p]=a[++j];
for(int i=l;i<=r;i++)a[i]=temp[i];
}
在歸併排序中,無非就是將「兩個有序陣列」變成「乙個被一分為二的陣列(也
是兩個)」——因為不斷二分後,剩下的單個元素必定有序,所以合併相鄰相
鄰元素並使之有序,之後產生兩個有序區間等價於合併兩個有序陣列。但
此處仍有值得注意的地方,就是由於兩個陣列的大小關係具有不確定性,在第
乙個while結束後兩個原陣列中有剩餘的元素未參與排序,所以需要再加兩個
while來處理剩餘元素(此時一定是只會執行其中的乙個while,原因不言自
明)。最後,一定要把過程陣列temp覆蓋原陣列a的值,保證每次傳遞
到上一級區間(大區間)的數值都有序。
穩定複雜度:o(nlogn)
三、關於為何引進歸併排序
大家可以發現,歸併排序每次的操作只針對相鄰區間,或者說合併時是對相鄰幾個區間的操作,所以這符合只需要修改相鄰幾個分數的排布狀況的題意。即使和快排的複雜度相同,但是省掉了冗雜無用的操作,是乙個極大的改良。
最後,附ac**:
#include#includeusing namespace std;
int n,r,q;
int a[200100],win[200100],lose[200100];
int s[200100],w[200100];
bool cmp(int x,int y)
void merge()
int main()
else
merge();
} cout<
洛谷P1309 瑞士輪
本題同樣是noip普及組第三題。因為太久沒有做過題目了,先從普及組開始練習吧。題目內容 很顯然想到的思路就是模擬,如下 include include include include using namespace std struct player bool cmp player a,player...
洛谷p1309 瑞士輪
因為太菜不會寫p1310 表示式的值,就只能過來水兩篇部落格啦qwq 另外這個題我是開o2才過的 雖然是寫了歸併排序 可能我太菜寫的歸併不是還可以 剪枝 吧qwq 哎,果真還是太菜啦qwq 所以準備寫歸併然後去題解學習正確的不用開o2就可以過的演算法 瑞士輪 題目鏈結 其實這個題打眼一看可以直接so...
洛谷 P1309 瑞士輪
在雙人對決的競技性比賽,如桌球 羽毛球 西洋棋中,最常見的賽制是淘汰賽和迴圈賽。前者的特點是比賽場數少,每場都緊張刺激,但偶然性較高。後者的特點是較為公平,偶然性較低,但比賽過程往往十分冗長。本題中介紹的瑞士輪賽制,因最早使用於1895年在瑞士舉辦的西洋棋比賽而得名。它可以看作是淘汰賽與迴圈賽的折中...