# 題目: UVa 10616 - Divisible Group Sums
# 題目說明
給一個有 N
個數字的序列,取出 M
個數字相加,使結果能整除 D
,求總方法數
INPUT:
每筆測資第一行輸入兩個整數 N
、 Q
接下來有 N
行,每行輸入一個整數
接下來有 Q
行,每行輸入兩個整數 D
、 M
當 N
、 Q
為 0
時結束程式
OUTPUT:
輸出符合題目條件的總方法數
# 解題方法
此題為 knapsack problems
(背包問題)
需要先將輸入的 N
個數字 ( num[i]
) 做處理
- 若為正數,
num2[i] = num[i] % D
,直接取D
的餘數 - 若為負數,
num2[i] = num[i] % D + D
,取D
的餘數後加D
,使之變正數
定義一個 dp[j][k]
j
為當前取到的數值k
為取幾個數
轉移方程為 dp[j][k] += dp[j - num2[f]][k - 1]
最後將所有 dp[D的倍數][M]
相加為答案
由於題目限制為 32 bit
的有號整數,所以需要用 long long
以防 overflow
# 參考程式碼
#include <iostream> | |
#include <vector> | |
#include <memory.h> | |
using namespace std; | |
int main() | |
{ | |
ios::sync_with_stdio(false); | |
cin.tie(nullptr); | |
cout.tie(nullptr); | |
int N, Q, D, M; | |
int a, cases = 0; | |
long long dp[201][11]; | |
while (cin >> N >> Q, N && Q) | |
{ | |
vector<int> num; | |
while (N--) cin >> a, num.emplace_back(a); | |
cout << "SET " << ++cases << ":\n"; | |
for (int i = 1; i <= Q; ++i) | |
{ | |
cin >> D >> M; | |
vector<int> num2; | |
long long ans = 0; | |
memset(dp, 0, sizeof(dp)); | |
for (auto& j : num) num2.emplace_back(j % D > 0 ? j % D : j % D + D); | |
dp[0][0] = 1; | |
for (int f = 0; f < num2.size(); ++f) for (int j = 200; j >= num2[f]; --j) | |
for (int k = M; k > 0; --k) dp[j][k] += dp[j - num2[f]][k - 1]; | |
for (int j = 0; j <= 200; j += D) ans += dp[j][M]; | |
cout << "QUERY " << i << ": " << ans << "\n"; | |
} | |
} | |
return 0; | |
} |
# 參考資料
https://blog.csdn.net/mobius_strip/article/details/41252307
https://summon528.github.io/2017/12/05/UVA-10616-Divisible-Group-Sums/