P1356题解
传送门:https://www.luogu.com.cn/problem/P1356
非常明显的背包问题,体积即为模 \(k\) 的结果。用布尔状态 \(dp_{i,j}\) 表示前 \(i\) 位是否存在模 \(k\) 为 \(j\) 的结果。负数看上去比较麻烦,设其为 \(x\),令 \(x\leftarrow (x + \lceil \frac{-x}{k} \rceil \times k) \ mod \ k\),非负数直接模 \(k\) 即可。我们发现所有 \(a_i\) 均小于 \(k\) 时我们能得到一个异常简洁的转移方程。
\[dp_{i,j} = dp_{i-1,(j - a_i + k) \% k} \lor dp_{i-1,(j + a_i) \% k}
\]
可以用滚动数组优化空间。最终时间复杂度 \(O(nk)\),空间复杂度 \(O(k)\)。
#include <bits/stdc++.h>
const int N = 5e5 + 1;
using namespace std;
int dp[1000][2];
int main() {
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int T;
cin >> T;
while (T--) {
int n, k, now = 0;
cin >> n >> k;
for (int j = 0; j < k; ++j) dp[j][0] = 0;
dp[0][0] = 1;
for (int i = 1; i <= n; ++i) {
int num;
cin >> num;
if (num < 0) num += (-num / k + (-num % k != 0)) * k;
else num %= k;
now ^= 1;
for (int j = 0; j < k; ++j) dp[j][now] = 0;
for (int j = 0; j < k; ++j) dp[j][now] = dp[(j - num + k) % k][now ^ 1] | dp[(j + num) % k][now ^ 1];
}
if (dp[0][now]) cout << "Divisible" << '\n';
else cout << "Not divisible" << '\n';
}
return 0;
}

动态规划dp,背包dp
浙公网安备 33010602011771号