標題:對局匹配
小明喜歡在一個圍棋網站上找別人在線對弈。這個網站上所有注冊用戶都有一個積分,代表他的圍棋水平。
小明發現網站的自動對局系統在匹配對手時,只會將積分差恰好是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
如有不當之處歡迎指出!