2021牛客寒假算法基础集训营5 - D石子游戏

前言:哎,这场打的就很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;
        }
    }

}

你可能感兴趣的