前言:哎,这场打的就很nanshou,开局a出俩题,剩下的数学题兴趣就直接无了,结果俩小时直接结束战斗。
结束之后看了一下题解,感觉D题讲的有点麻烦,这边讲一下一种更低效率不过更加直观的做法。如果有看不懂题解的朋友可以尝试一下我的理解。
没看过题目的可以去牛客先看一下。我这里自己出一组数据。
1
5 2
3 3 2 0 2
这里介绍一个算法,差分算法,至于为什么想到的,只能说看到这题就本能的就想到这个算法。
我们对数据进行差分(就是前一个数减后一个数)。得到差分数组cut。
0 1 2 -2
然后我们从左到右推,每次遇到一个数 cut[i] 为正就让cut [ i+k ]加上cut [ i ],cut [i] = 0。注意这里的i+k必须小于等于n(这里是5)。至于为什么后面解释。
然后变成了
0 0 0 -1(2)(最后一个2是前面推来的,在位置n上,我们不需要这个数)
然后从右往左,每次遇到cut [ i ]为负数就让cut [ i - k ] += cut [ i ],cut [ i ] = 0。注意i+k>=0。
然后变成
(-1) 0 0 0 0 (2)
这里面的位置为1到4都是0,所以可以得出结果。
然后解释一下我们为什么做这种操作,我下面列一些变化过程。
3 3 2 0 2 cut:0 1 2 -2
3 3 3 1 2 cut:0 0 2 -1
3 3 3 3 4 cut:0 0 0 -1 (2)
3 3 4 4 4 cut:0 -1 0 0 (2)
4 4 4 4 4 cut:(-1) 0 0 0 0 (2)
懂了吧?因为一次操作的区间为k,所以差分数组会变化的只有i和i+k或i和i-k。
假如i+k>n或者i-k<0,则是不可能的,我们也举个例子。
k=2,3 4 4 4 4 , cut:-1 0 0 0
我们就无法把这个-1给清除掉,因为这涉及数组外的数了。
下面给出代码,速度还有很大的空间可以优化,但是没必要
//
// Created by acer on 2021/2/21.
//
#include
using namespace std;
#define int long long
const int maxn = 2e5 + 10;
int num[maxn];
int cut[maxn];
signed main() {
int T;
cin >> T;
while (T--) {
memset(cut, 0, sizeof(cut));
int n, k;
int sum = 0;
cin >> n >> k;
for (int i = 1; i <= n; ++i) {
cin >> num[i];
if (i >= 2)
cut[i - 1] = num[i - 1] - num[i];
}
for (int j = 1; j <= n - 1; ++j) {
//正推
if (cut[j] < 0) {
if (j - k < 0) continue;
} else {
if (j + k <= n) {
sum += cut[j];
cut[j + k] += cut[j];
cut[j] = 0;
}
}
}
for (int i = n - 1; i >= 1; --i) {
//反推
/*for (int j = 1; j <= n - 1; ++j) {
cout << cut[j] << ' ';
}
cout << endl;*/
if (cut[i] < 0) {
if (i - k > 0) {
cut[i - k] += cut[i];
sum += abs(cut[i]);
cut[i] = 0;
} else if (i - k == 0) {
sum += abs(cut[i]);
cut[i] = 0;
} else if (i - k < 0) {
break;
}
}
}
int l;
for (l = 1; l <= n - 1; ++l) {
if (cut[l] != 0) break;
}
if (l != n)
cout << -1 << endl;
else {
cout << sum << endl;
}
}
}