洛谷題目鏈接:瑞士輪
題目背景
在雙人對決的競技性比賽,如乒乓球、羽毛球、國際象棋中,最常見的賽制是淘汰賽和循環賽。前者的特點是比賽場數少,每場都緊張刺激,但偶然性較高。后者的特點是較為公平,偶然性較低,但比賽過程往往十分冗長。
本題中介紹的瑞士輪賽制,因最早使用於1895年在瑞士舉辦的國際象棋比賽而得名。它可以看作是淘汰賽與循環賽的折中,既保證了比賽的穩定性,又能使賽程不至於過長。
題目描述
2*N 名編號為 1~2N 的選手共進行R 輪比賽。每輪比賽開始前,以及所有比賽結束后,都會按照總分從高到低對選手進行一次排名。選手的總分為第一輪開始前的初始分數加上已參加過的所有比賽的得分和。總分相同的,約定編號較小的選手排名靠前。
每輪比賽的對陣安排與該輪比賽開始前的排名有關:第1 名和第2 名、第 3 名和第 4名、……、第2K – 1 名和第 2K名、…… 、第2N – 1 名和第2N名,各進行一場比賽。每場比賽勝者得1 分,負者得 0 分。也就是說除了首輪以外,其它輪比賽的安排均不能事先確定,而是要取決於選手在之前比賽中的表現。
現給定每個選手的初始分數及其實力值,試計算在R 輪比賽過后,排名第 Q 的選手編號是多少。我們假設選手的實力值兩兩不同,且每場比賽中實力值較高的總能獲勝。
輸入輸出格式
輸入格式:
輸入文件名為swiss.in 。
輸入的第一行是三個正整數N、R 、Q,每兩個數之間用一個空格隔開,表示有 2*N 名選手、R 輪比賽,以及我們關心的名次 Q。
第二行是2*N 個非負整數s1, s2, …, s2N,每兩個數之間用一個空格隔開,其中 si 表示編號為i 的選手的初始分數。 第三行是2*N 個正整數w1 , w2 , …, w2N,每兩個數之間用一個空格隔開,其中 wi 表示編號為i 的選手的實力值。
輸出格式:
輸出文件名為swiss.out。
輸出只有一行,包含一個整數,即R 輪比賽結束后,排名第 Q 的選手的編號。
輸入輸出樣例
說明
【樣例解釋】
【數據范圍】
對於30% 的數據,1 ≤ N ≤ 100;
對於50% 的數據,1 ≤ N ≤ 10,000 ;
對於100%的數據,1 ≤ N ≤ 100,000,1 ≤ R ≤ 50,1 ≤ Q ≤ 2N,0 ≤ s1, s2, …, s2N≤10^8,1 ≤w1, w2 , …, w2N≤ 10^8。
noip2011普及組第3題。
首先看到題目,第一眼想到的是排序模擬,然后算了一下直接快排的時間復雜度,O(nlogn+r*(nlogn+n)),感覺如果沒有極限數據是可以卡過去的,然后我就意識到了這個想法是多么的愚蠢,但是事實並非如此,所以直接快排是肯定不行的.於是我們來想一下如何才能優化這個排序.
我們仔細想一下,每個比較都是從前往后依次比較過來的,那么先贏的人肯定在后贏的人前面,先輸的人也一定在后輸的人前面.
為什么會這樣呢?我們假設數據已經是按照當前的分數排名成有序的,那么在前面的人的分數就一定比在后面的人的分數要高,那么同樣是贏的人,他們的分數都會在原來基礎上+1,那么先贏的人排完序之后也還是在后贏的人前面.
那么這個問題就被簡化了:每次一組勝利者,一組失敗者,將勝者與敗者按照分數為第一關鍵詞,編號為第二關鍵詞來排序.既然是兩組人進行合並,那么就可以用歸並排序來加快時間復雜度.優化后時間復雜度O(nlogn+r*n).
下面上代碼:
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N=200000+5; 4 5 int n, m, q; 6 int id[N]; 7 int win[N]; 8 int lose[N]; 9 int mark[N]; 10 int v[N]; 11 12 bool cmp(int a,int b){ 13 if(mark[a] != mark[b]) return mark[a] > mark[b]; 14 return a < b; 15 } 16 17 int gi(){ 18 int ans = 0 , f = 1; char i = getchar(); 19 while(i<'0'||i>'9'){if(i=='-')f=-1;i=getchar();} 20 while(i>='0'&&i<='9'){ans=ans*10+i-'0';i=getchar();} 21 return ans * f; 22 } 23 24 void merge(){ 25 int i = 1 , j = 1; id[0] = 0; 26 while(i<=win[0] && j<=lose[0]) 27 if(cmp(win[i],lose[j])) id[++id[0]] = win[i++]; 28 else id[++id[0]] = lose[j++]; 29 while(i<=win[0]) id[++id[0]] = win[i++]; 30 while(j<=lose[0]) id[++id[0]] = lose[j++]; 31 } 32 33 int main(){ 34 //freopen("data.in","r",stdin); 35 n = gi(); m = gi(); q = gi(); n *= 2; 36 for(int i=1;i<=n;i++) mark[i] = gi(); 37 for(int i=1;i<=n;i++) v[i] = gi() , id[i] = i; 38 sort(id+1 , id+n+1 , cmp); 39 for(int i=1;i<=m;i++){ 40 win[0] = lose[0] = 0; 41 for(int j=1;j<=n;j+=2){ 42 if(v[id[j]] > v[id[j+1]]){ 43 mark[id[j]]++; 44 win[++win[0]] = id[j]; 45 lose[++lose[0]] = id[j+1]; 46 } 47 else{ 48 mark[id[j+1]]++; 49 win[++win[0]] = id[j+1]; 50 lose[++lose[0]] = id[j]; 51 } 52 } 53 merge(); 54 } 55 cout << id[q] << endl; 56 return 0; 57 }