1. 程式人生 > >【題解】誰會贏?

【題解】誰會贏?

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 
+ 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(n²)版

我們可以發現,我們不斷縮小的區間本身就是滿足單調性的,那我們其實可以用二分查找來縮小區間,使時間復雜度降到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)版

【題解】誰會贏?