1. 程式人生 > >第八屆藍橋杯決賽 對局匹配

第八屆藍橋杯決賽 對局匹配

標題:對局匹配

小明喜歡在一個圍棋網站上找別人線上對弈。這個網站上所有註冊使用者都有一個積分,代表他的圍棋水平。
小明發現網站的自動對局系統在匹配對手時,只會將積分差恰好是K的兩名使用者匹配在一起。如果兩人分差小於或大於K,系統都不會將他們匹配。
現在小明知道這個網站總共有N名使用者,以及他們的積分分別是A1,A2,...AN
小明想了解最多可能有多少名使用者同時線上尋找對手,但是系統卻一場對局都匹配不起來(任意兩名使用者積分差不等於K)?

輸入

第一行包含兩個個整數N和K。
第二行包含N個整數A1, A2, … AN。
對於30%的資料,1 <= N <= 10
對於100%的資料,1 <= N <= 100000, 0 <= Ai <= 100000, 0 <= K <= 100000

輸出

一個整數,代表答案。

樣例輸入:

10 0
1 4 2 8 5 7 1 4 2 8

樣例輸出:

6

樣例輸入:

10 1
2 1 1 1 1 4 4 3 4 4

樣例輸出:

8

資源約定:
峰值記憶體消耗 < 256M
CPU消耗 < 1000ms
請嚴格按要求輸出,不要畫蛇添足地列印類似:“請您輸入…” 的多餘內容。
所有程式碼放在同一個原始檔中,除錯通過後,拷貝提交該原始碼。
注意: main函式需要返回0
注意: 只使用ANSI C/ANSI C++ 標準,不要呼叫依賴於編譯環境或作業系統的特殊函式。
注意: 所有依賴的函式必須明確地在原始檔中 #include , 不能通過工程設定而省略常用標頭檔案。

提交時,注意選擇所期望的編譯器型別。

思路

  如果把n個元素按照將分數相差為k的使用者分成一組,例如第一組就是{0,k,2k,3k...},第二組就是{1,k+1,2k+1...},等等。這樣分組的話,每個分組的使用者是不可能和其他分組的使用者匹配成功的,因為分差不可能為k
  這樣的話,只要在每個分組裡面選取儘量多的使用者就可以了。用cnt(i)表示分數為i的使用者人數,假設現在第i組有m個不同分數{x,x+k,x+2k,...,x+(m1)k

},其中x表示該組第一個人的積分,那麼用動態規劃法來選擇儘量多的人數。dp(j)表示選擇前j個分數能獲得的最大使用者人數(價值),很明顯如果選擇第j個分數,那麼第j1個分數是不能選的,因為它們的積分相差k,該組最大線上人數為dp(m)
  狀態轉移方程如下:

dp(i)=max{dp(i1),dp(i2)+cnt(score)}

  其中cnt(score)表示積分為第i個分數的總人數。是否感覺上述動態方程與01揹包很類似?
需要注意的是,k=0要特殊處理。

演算法複雜度

O(100000),只與最大分數有關。

AC程式碼

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
#define MAX_SCORE 100000
const int maxn = 100000 + 5;
int cnt[MAX_SCORE+5], val[maxn], dp[maxn];
int n, k;

int main() {
    while(scanf("%d%d", &n, &k) == 2) {
        memset(cnt, 0, sizeof(cnt));
        int score, ans = 0;
        for(int i = 1; i <= n; i++) {
            scanf("%d", &score);
            cnt[score]++;
        }
        //特殊處理k=0的情況
        if(k == 0) {
            for(int i = 0; i <= MAX_SCORE; i++) {
                if(cnt[i]) ans++;
            }
        } 
        else {
            for(int i = 0; i < k; i++) {
                int m = 0;
                for(int j = i; j <= MAX_SCORE; j+=k) {
                    val[m++] = cnt[j];
                }
                dp[0] = val[0];
                for(int j = 1; j < m; j++) {
                    if(j == 1) dp[j] = max(dp[0], val[j]);
                    else dp[j] = max(dp[j-2] + val[j], dp[j-1]);
                }
                ans += dp[m-1];
            }
        }
        printf("%d\n", ans);
    }
    return 0;
}

如有不當之處歡迎指出!