給 n (≤ 10000) 個整數,在其間填 + 或 -,使表達式結果能被 k (≤ 100) 整除。輸出 "Divisible" 或 "Not divisible"。
`dp[i][j]` = 前 i 個數能否構造出模 k 餘 j 的值。i=1..n, j=0..k-1。
初始:`dp[1][(a[1]%k+k)%k] = true`。
轉移:對第 i 個數 `x = (a[i]%k+k)%k`,
`dp[i][(j+x)%k] |= dp[i-1][j]` (加)
`dp[i][(j-x+k)%k] |= dp[i-1][j]` (減)
答案:`dp[n][0]`。
只需 `dp[2][k]`,當前行 `cur = i&1`,上一行 `pre = (i-1)&1`。每輪清空 `cur` 行再轉移。
#include
#include
const int MAXN = 10005;
bool dp[2][105];
int a[MAXN];
int main() {
int n, k;
while (~scanf("%d%d", &n, &k)) {
for (int i = 1; i <= n; ++i) {
scanf("%d", &a[i]);
a[i] = (a[i] % k + k) % k; // 規範到 [0, k-1]
}
memset(dp, 0, sizeof(dp));
dp[1][a[1]] = true;
for (int i = 2; i <= n; ++i) {
int cur = i & 1, pre = (i-1) & 1;
memset(dp[cur], 0, sizeof(dp[cur]));
for (int j = 0; j < k; ++j) if (dp[pre][j]) {
dp[cur][(j + a[i]) % k] = true;
dp[cur][(j - a[i] + k) % k] = true;
}
}
puts(dp[n&1][0] ? "Divisible" : "Not divisible");
}
return 0;
}
POJ 1745 是「模 k 線性 DP」的標準模板題。狀態為模 k 餘數,轉移為加減當前數。滾動數組優化空間,預處理模 k 簡化邏輯。掌握此模板,可解決所有「加減號組合整除性」問題。