zoukankan      html  css  js  c++  java
  • USACO20OPEN Haircut G

    题目链接

    Solution

    不会做,于是参考题解

    假设现在 (mathrm{John}) 不再需要为肆意生长的头发而烦恼了,而是成为了一个因秃头而抓狂的脱发人士。现在,我们把理发看成是生发,那么第 (i) 根头发的极限长度就是 (a_i).

    头发从 (0) 开始生长,在到达极限长度之前,每秒生长 (1) 个单位长度。现在我们把题目中的 (j) 看成是时间,那么第 (j) 秒头发最长一定不会超过 (j). 这不是正好符合题目限制吗?

    显而易见的,第 (0) 秒的逆序对个数是 (0). 那么,我们现在需要考虑的是第 (j)新增的逆序对。如果第 (i) 根头发的最大高度 (a_i = j - 1),说明第 (j) 秒它已经停止生长了。当 (j-1) 秒时,那些跟它比肩的小伙伴(指还未停止生长的头发)很可能借助从这一秒开始超过它。

    也就是说,当满足 (j < i)(a_j > a_i) 时,从第 (a_i + 1)开始(i)(j) 为答案贡献逆序对。观察前半句话,这还是个求逆序对,可以用树状数组维护;对于后半句话,就涉及区间加法了。因为这题不需要多次询问,因此直接差分即可。总时间复杂度 (mathrm{O(nlog_n)}).

    Code

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #define LL long long
    #define lowbit(x) (x & (-x))
    using namespace std;
    
    const int N = 2333333;
    LL n, a[N], sum[N], t[N];
    
    void add(LL x) { while(x <= n + 1) t[x]++, x += lowbit(x); }
    LL query(LL x)
    {
        LL res = 0;
        while(x) res += t[x], x -= lowbit(x);
        return res;
    }
    
    int main()
    {
        scanf("%lld", &n);
        memset(t, 0, sizeof(t));
        memset(sum, 0, sizeof(sum));
        for(int i = 1; i <= n; i++)
        {
            scanf("%lld", &a[i]), a[i]++;
            sum[a[i] + 1] += query(n + 1) - query(a[i]);
            add(a[i]);
        }
        for(int i = 1; i <= n; i++)
        {
            sum[i] += sum[i - 1];
            printf("%lld
    ", sum[i]);
        }
        return 0;
    }
    
  • 相关阅读:
    四则运算
    四则运算二
    学习进度条
    四则运算一
    课堂测试七
    问题与思考6
    问题与思考5
    问题与思考04
    Android SDK 目录说明
    如何判断视频的比例(4:3/16:9)和分辨率?
  • 原文地址:https://www.cnblogs.com/Andy-park/p/14069680.html
Copyright © 2011-2022 走看看