Codeforces Global Round 13 C

Codeforces Global Round 13 C

大意

略...

思路

首先想到,如果一直贪心选择第一个数,可以得到最优解,证明如下:

考虑第k位的数 \(a_k\) , 在将其变为1的过程中,所有 \(k+2\)\(k+a_k\) 的数都会被免费遍历到一次。

也就是说,无论顺序如何,只要最后整个数组全为1, 那么对于每一个数 \(a_i\) ,再将其变为1的过程中, \(i+2\)\(i+a_i\) 一定都会被免费遍历一次。

容易发现,每一个位置的免费遍历的次数的最大值是确定的,而当我们贪心选择时,总能让所有位置达到最大值。

因为免费遍历的位置只能在选择消减的数之后,所以我们贪心将 \(a_1\) 变为1,然后,再贪心于 \(a_1\) 就相当于选择了 \(a_2\) ,此时 \(a_2\) 的免费遍历次数显然最大,归纳易得上述发现。

考虑如何求解。

对于第k位的数 \(a_k\) ,假设已知其免费遍历次数为 \(c\) ,那么会有如下三种情况:

  1. \(2 \leq a_k - c\)

    此时,经过免费遍历后 \(a_k > 1\) 所以还需 \(a_k-c-1\) 次才能使其变为1。

    同时 \(k+2\)\(k+a_k\) 的数都会被免费遍历一次。

  2. \(a_k -c = 1\)

    此时,\(a_k\) 正好变为1

  3. \(a_k - c < 1\)

    这种情况比较特殊,

    \(a_k\) 的免费遍历次数超过了本身的值。

    观察题意会发现,超过的次数会转移到 \(k+1\) 位。

代码

时间复杂度 \(\Theta(NlogN)\)

我是直接复制的树状数组模板,因为是按顺序访问并添加,可以换成手写差分,于是时间复杂度 \(\Theta(N)\)

#include <map>
#include <set>
#include <cmath>
#include <queue>
#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

#define ll long long
#define ull unsigned long long
#define cint const int&
#define Pi acos(-1)

const int mod = 1e9+7;
const int inf_int = 0x7fffffff;
const ll inf_ll = 0x7fffffffffffffff;
const double ept = 1e-9;

int t;
int n;
int a[5050];
int r[5050];

int lowbit(cint x) { return x&-x; }

void add_p(int loc, cint num) {
    while(loc <= n) {
        r[loc] += num;
        loc = loc + lowbit(loc);
    }
}

int get_r(int x) {
    // 1~x
    int ans = 0;
    while(x) {
        ans += r[x];
        x -= lowbit(x);
    }
    return ans;
}

int main() {
    cin >> t;
    while(t--) {
        cin >> n;
        for(int i=1; i<=n; i++) cin >> a[i], r[i] = 0;
        ll ans = 0;
        for(int i=1; i<=n; i++) {
            int s = get_r(i);
            // cout << i << ' ' << a[i] << ' ' << s << endl;
            if(a[i] - s >= 1) {
                ans += a[i]-s-1;
            } else {
                add_p(i+1, s-a[i]+1);
                add_p(i+2, -(s-a[i]+1));
            }
            add_p(i+2, 1);
            add_p(min(n+1, i+a[i]+1), -1);
        }
        cout << ans << endl;
    }
    return 0;
}

45min, -4

posted @ 2021-03-07 16:01  ullio  阅读(42)  评论(0编辑  收藏  举报