abc419E
用肉眼发现\(a_i和a_{i+L}\)之间有微妙的关系,再仔细观察,对于限制\(a_i\)到\(a_{i+L-1}\)和\(a_{i+1}\)到\(a_{i+L}\)之间有公共部分\(a_{i+1}\)到\(a_{i+L}\),所以不难发现\(a_i = a_{i+L}\) \(mod\) \(m\),因此我们关注前\(L\)个数就可以确定接下来所有数了。
然后用脚写dp,令\(f_{i,j}\)表示前\(i\)个数的和\(mod\) \(m\)等于\(j\)的最少操作次数。我们枚举当前位置选的数和前一个位置选的数就行了。\(sum\)表示第\(i\)个位置变成某个数的代价(对于限制内计算,具体看代码),接下来转移方程是(看代码hhh)。
后面只需提交即可
别复制我代码!!!
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n, m, L, a[10010], ans = 0, f[510][510];
vector <int> v[10010];
signed main() {
cin >> n >> m >> L;
for (int i = 1; i <= n; i++) {
scanf("%lld", &a[i]);
}
for (int i = 1; i <= L; i++) {
int now = i;
while (now <= n) {
v[i].push_back(a[now]);
now += L;
}
}
memset(f, 127, sizeof(f));
f[0][0] = 0;
for (int i = 1; i <= L; i++) {
for (int j = 0; j < m; j++) {
int sum = 0;
for (auto k : v[i]) {
if (k <= j) sum += j - k;
else sum += (j - k) % m + m;
}
for (int k = 0; k < m; k++) {
f[i][(k + j) % m] = min(f[i][(k + j) % m], f[i - 1][k] + sum);
}
}
}
cout << f[L][0];
}
浙公网安备 33010602011771号