AT_abc419_e 题解
设操作结束后的序列为 \(B=(B_1,B_2,...,B_n)\)。首先可以注意到,如果 \(i = j + L\),那么 \(B_i \equiv B_j \pmod M\)。很好证明,根据题意,\(B_i+B_{i+1}+...+B_{j-1} \equiv 0 \pmod M\),\(B_{i+1}+B_{i+2}+...+B_j \equiv 0 \pmod M\),两式相减,得 \(B_i-B_j \equiv 0 \pmod M\),移项就能得到 \(B_i \equiv B_j \pmod M\)。
所以先设 \(f_{i,j}\) 为前 \(i\) 个数中与 \(i\) 模 \(L\) 同余的所有数都改为对 \(M\) 取模为 \(j\) 的数的最少操作次数,递推方程:
\[f_{i,j}=f_{i-L,j}+\operatorname {cg(A_i,j)}
\]
其中 \(\operatorname {cg(A_i,j)}\) 的意思是将 \(A_i\) 改为对 \(M\) 取模为 \(j\) 的数的最少操作次数。
为了满足题意,还有一个条件,就是存在一个长度为 \(L\) 的连续子数组和为 \(M\) 的倍数。可以用分组背包,详见代码。
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
int n, m, l, a[505], q[505], f[505][505], g[505][505];
void init() {
for (int i = 0; i < 505; i++)
for (int j = 0; j < 505; j++)
g[i][j] = 2147483647;
}
int cg(int x, int y) {
x %= m; y %= m;
if (x <= y) return (y - x);
return (y + m - x);
}
signed main() {
std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
cin >> n >> m >> l;
for (int i = 1; i <= n; i++) cin >> a[i], q[i] = q[i - 1] + a[i];
init();
f[0][0] = 0;
for (int i = 1; i <= n; i++)
for (int j = 0; j < m; j++) {
if (i <= l) f[i][j] = cg(a[i], j);
else f[i][j] = f[i - l][j] + cg(a[i], j);
}
g[0][0] = 0;
for (int i = 1; i <= l; i++)
for (int j = 0; j < m; j++)
for (int k = 0; k < m; k++)
g[i][j] = min(g[i][j], g[i - 1][(j - k + m) % m] + f[n - (l - i)][k]);
cout << g[l][0] << endl;
return 0;
}

浙公网安备 33010602011771号