【題解】誰會贏?
阿新 • • 發佈:2019-02-05
color 是否 lns one int img 分享 lse sin
題目描述
最近,在課余時間流行一種遊戲,遊戲的規則如下:遊戲開始時,每個人都從規定範圍內的數中選取一個數(保證所選取的數各不相同),寫在紙上,握在手中(以防讓別的同學看見),然後同時打開,如果其中一個同學手中的數是其他任意兩位同學手中的數之和,那麽他就贏,如果滿足條件的有多個,手中的數最大的那位同學贏。這是心理和智力的雙重考驗,所以參加的學生越來越多。但是,由於參與人數眾多,要判斷誰贏就成了問題,請聰明的你設計一個程序來解決這個問題!
輸入輸出格式
輸入格式
第一行為一個整數N(3≤N≤50000),表示參加遊戲的總人數,第二行為N個數(範圍在0- 231231之間),依次表示N個同學所選的數,第i個數表示第i位同學所選的數。
輸出格式
一行,為一個整數,表示哪位同學贏。如果沒有任何一位同學贏,則輸出“0”。
輸入輸出樣例
輸入樣例
5
2 5 7 3 12
輸出樣例
5
題解
樸素做法是枚舉兩個數,然後判斷第三個數是否存在,用二分或平衡樹等能做到O(n²logn)的時間復雜度,用哈希表可以更快,時間復雜度接近O(n²),但顯然這種做法不滿足題目需求。
我們可以換一個角度思考,枚舉和,然後枚舉加數,加數實際上可以用一重循環就枚舉出來。我們可以排序之後不斷縮小枚舉區間來找加數,這樣就能做到O(n²)的時間復雜度。具體看下面的代碼。
#include <iostream> #include <cstdio> #define MAX_N 50001 using namespace std; int n; struct Node { int idx; int val; }; Node a[MAX_N | 1], b[MAX_N | 1]; void Sort(int lt, int rt) { if(lt == rt) return; int mid = lt + rt >> 1; Sort(lt, mid); Sort(mid參考程序O(n²)版+ 1, rt); int i = lt, j = mid + 1; int cnt = 0; while(i <= mid && j <= rt) { if(a[i].val < a[j].val) b[++cnt] = a[i++]; else b[++cnt] = a[j++]; } while(i <= mid) { b[++cnt] = a[i++]; } while(j <= rt) { b[++cnt] = a[j++]; } for(i = 1; i <= cnt; ++i) { a[lt + i - 1] = b[i]; } return; } int main() { scanf("%d", &n); for(register int i = 1; i <= n; ++i) { scanf("%d", &a[i].val); a[i].idx = i; } Sort(1, n); for(register int k = n; k; --k) { for(register int i = 1, j = k - 1; i < j;) { while(i < j && a[i].val + a[j].val < a[k].val) ++i; while(i < j && a[i].val + a[j].val > a[k].val) --j; if(a[i].val + a[j].val == a[k].val) return printf("%d", a[k].idx), 0; } } putchar(‘0‘); return 0; }
我們可以發現,我們不斷縮小的區間本身就是滿足單調性的,那我們其實可以用二分查找來縮小區間,使時間復雜度降到O(nlogn),這樣就能完美解決這道題了。
#include <iostream> #include <cstdio> #define MAX_N 50001 using namespace std; int n; struct Node { int idx; int val; }; Node a[MAX_N | 1], b[MAX_N | 1]; int Read() { int res = 0; char ch = getchar(); while(ch < ‘0‘ || ch > ‘9‘) ch = getchar(); while(ch >= ‘0‘ && ch <= ‘9‘) res = res * 10 + ch - ‘0‘, ch = getchar(); return res; } void Sort(int lt, int rt) { if(lt == rt) return; int mid = lt + rt >> 1; Sort(lt, mid); Sort(mid + 1, rt); int i = lt, j = mid + 1; int cnt = 0; while(i <= mid && j <= rt) { if(a[i].val < a[j].val) b[++cnt] = a[i++]; else b[++cnt] = a[j++]; } while(i <= mid) { b[++cnt] = a[i++]; } while(j <= rt) { b[++cnt] = a[j++]; } for(i = 1; i <= cnt; ++i) { a[lt + i - 1] = b[i]; } return; } int main() { n = Read(); for(register int i = 1; i <= n; ++i) { a[i].val = Read(); a[i].idx = i; } Sort(1, n); int lt, rt, mid; int op; for(register int k = n; k; --k) { for(register int i = 1, j = k - 1; i < j;) { op = 0; if(a[i].val + a[j].val < a[k].val) { lt = i + 1; rt = j - 1; while(lt <= rt) { mid = lt + rt >> 1; if(a[mid].val + a[j].val < a[k].val) lt = mid + 1; else op = 1, i = mid, rt = mid - 1; } } if(a[i].val + a[j].val > a[k].val) { lt = i + 1; rt = j - 1; while(lt <= rt) { mid = lt + rt >> 1; if(a[i].val + a[mid].val > a[k].val) rt = mid - 1; else op = 1, j = mid, lt = mid + 1; } } if(a[i].val + a[j].val == a[k].val) { printf("%d", a[k].idx); return 0; } if(!op) break; } } putchar(‘0‘); return 0; }參考程序O(nlogn)版
【題解】誰會贏?