zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    声律启蒙(上 下卷,珍藏版)
    笠翁对韵(全卷,珍藏版附注释)
    Oracle 中 nvl、nvl2、nullif、coalesce、decode 函数的用法详解
    Groovy
    spring各版本jar包和源码
    Java 调用翻译软件实现英文文档翻译
    oracle导出序列的几种办法
    Oracle数据库内存使用情况分析查看
    window Maven私服搭建——nexus
    用户管理的备份与恢复
  • 原文地址:https://www.cnblogs.com/ullio/p/14495010.html
Copyright © 2011-2022 走看看