1. 程式人生 > >UVa Live 7147 貪心(2014 上海區域賽)

UVa Live 7147 貪心(2014 上海區域賽)

題目連結

這個題已經過了一年了。。。本來當時就想寫題解但是沒找到題。。最近有人問我才知道原來UVa Live有歷年題目。。。

去年在現場的時候這題也是卡了好久。。。重寫了兩三次。。封榜了才過。。

題意:有n只隊伍,每隻隊伍要和其他n-1只隊伍比賽,每場比賽獲勝得a分,平局得b分,敗北得c分,共有m只隊伍可以晉級,問最高淘汰分和最低晉級分分別是多少。

思路:這個題的細節真的很多。。

首先如果獲勝分<敗北分,互換兩個分數。

然後考慮分數儘量平均的分配方式:

在偶數個人中,想讓所有人分數相等有兩種方式,所有人平局或贏一半的人輸一半的人;

在奇數個人中,要麼所有人平局,要麼一部分人多輸一局。

最高淘汰分:第m+1人,對於其後面的n-m-1人都應該選擇贏或者平局,對於前面的m人,按照上面的分數分配方式選擇分較高的一種。

最低晉級分:第m人,對於其前面的m-1人都應該選擇輸或平局,對於後面的n-m人,按照上面的分數分配方式選擇分較少的一種。

這道題的細節很多,有一個需要注意的地方是對於奇數個人m,不應該比較m/2 * (win + lose)和 m * draw,這樣draw會多算一個,我就在這個地方卡了很久。。。(好像當時比賽的時候也在這裡卡了很久。。)

#include <iostream>
#include <algorithm>
using namespace std;

main() {
    long long n, m, win, draw, lose;
    int t, cas = 1;
    cin >> t;
    while(t--){
        cin >> n >> m >> win >> draw >> lose;
        if(win < lose) swap(win, lose);
        long long pass = 0, out = 0;
        if(m % 2 == 0){
            if(draw < lose) pass = draw * (n - 1);//如果平局分數最低 那麼最低晉級分就是所有人平局
            else {
                pass = (m - 1) * lose;//和前面的m-1人比一定是輸的
                long long p = n - m;
                pass += (p / 2) > 0 ? min(win + lose, draw + draw) * (p / 2) : 0;//和後面的人比,看哪種分數相同的情況分數最低
                if(p % 2) pass += min(draw, win);//如果是奇數情況,那麼要麼贏最後一名,要麼所有人平局,反正總分要低
            }
            if(draw > win) out = draw * (n - 1);//如果平局分數最低 那麼最高淘汰分就是所有人平局
            else{
                out = (m / 2) > 0? max(win + lose, draw + draw) * (m / 2) : 0;//和前面的人比,看哪種分數分數相同的情況分數最高
                out += (n - m - 1) * win;//和後面的人比一定是贏的
            }
        }
        else {
            if(draw < lose) pass = draw * (n - 1);
            else{
                pass = (m - 1) * lose;
                long long p = n - m;
                pass += (p / 2) > 0 ? min(win + lose, draw + draw) * (p / 2) : 0;
                if(p % 2) pass += min(win, draw);
            }
            if(draw > win) out = draw * (n - 1);
            else {
                out = (m / 2) > 0? max(win + lose, draw + draw) * (m / 2) : 0;
                out += max(draw, lose) + (n - m - 1) * win;//和前面的人比 如果是奇數情況 要麼平要麼輸 選分高的一種
            }
        }
        cout << "Case #" << cas++ << ": " << out << " " << pass << endl;
    }
}