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;
}
posted @ 2026-01-07 12:02  Jefferyzzzz  阅读(2)  评论(0)    收藏  举报