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


標題:對局匹配

小明喜歡在一個圍棋網站上找別人在線對弈。這個網站上所有注冊用戶都有一個積分,代表他的圍棋水平。
小明發現網站的自動對局系統在匹配對手時,只會將積分差恰好是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 , 不能通過工程設置而省略常用頭文件。

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


 思路

  設共有$x$種分數,將其分為$k$組,每個分數滿足相鄰的分數值相差為$k$。正如樣例2中所示,共有4種分數,將其分為1組:{1,2,3,4},這個組中任何相鄰的兩個分數都不能同時取,因為它們相差$k$,該分組還對應了一個人數分組:{4,1,1,4},要想使得人數盡量多,而且分數不能相差1,那么選擇分數分別為{1,4},人數是4+4=8.

  上述是只有一個分組的情況,當有多個分組的時候也是同樣的處理方法--盡量選擇不相鄰且人數最多。對於一個人數分別為$\{ {a_1},{a_2},...,{a_n}\}$的分組,可以利用動態規划算法來選擇最多人數,且都不相鄰。每個$a_i$只有選擇與不選擇兩種可能,假設$dp(i)$表示前i個人數能獲得的最多人數,那么選擇第i個人數的話,$dp(i)=dp(i-2)+a_i$,如果不選擇第i個人數的話,$dp(i)=dp(i-1)$,這樣得到轉移方程$dp(i) = \max \{ dp(i - 1),dp(i - 2) + {a_i}\} $。

  注意,當k=0的時候特殊處理一下。

 


 時間復雜度$O(MAX\_SCORE)$

AC代碼(借用@TQCAI的賬號已在藍橋杯官網AC)

 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <algorithm>
 4 using namespace std;
 5 #define MAX_SCORE 100000
 6 const int maxn = 100000 + 5;
 7 int cnt[MAX_SCORE+5], val[maxn], dp[maxn];
 8 int n, k;
 9 
10 int main() {
11     while(scanf("%d%d", &n, &k) == 2) {
12         memset(cnt, 0, sizeof(cnt));
13         int score, ans = 0;
14         for(int i = 1; i <= n; i++) {
15             scanf("%d", &score);
16             cnt[score]++;
17         }
18         //特殊處理k=0的情況
19         if(k == 0) {
20             for(int i = 0; i <= MAX_SCORE; i++) {
21                 if(cnt[i]) ans++;
22             }
23         } 
24         else {
25             for(int i = 0; i < k; i++) {
26                 int m = 0;
27                 for(int j = i; j <= MAX_SCORE; j+=k) {
28                     val[m++] = cnt[j];
29                 }
30                 dp[0] = val[0];
31                 for(int j = 1; j < m; j++) {
32                     if(j == 1) dp[j] = max(dp[0], val[j]);
33                     else dp[j] = max(dp[j-2] + val[j], dp[j-1]);
34                 }
35                 ans += dp[m-1];
36             }
37         }
38         printf("%d\n", ans);
39     }
40     return 0;
41 }

 

特此感謝@TQCAI


 

如有不當之處歡迎指出!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM