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;
}
posted @ 2025-08-17 16:13  wwqwq  阅读(25)  评论(0)    收藏  举报