zoukankan      html  css  js  c++  java
  • 河南省13届省赛-J.甜甜圈

    链接:https://ac.nowcoder.com/acm/contest/17148/J
    来源:牛客网

    艾洛喜欢吃甜食,他有n个甜甜圈,现在叠成了两叠(如下图所示),第一叠有n1个,第二叠有n2个(n1+n2=n),要解决的问题如下:

    • 每个甜甜圈都有一个唯一的甜度值sis_isi,甜度值两两不同;
    • 每次艾洛可以把任意一叠位于顶端的一个甜甜圈移动到另一叠顶端,若该甜甜圈是当前所有甜甜圈中最甜的(甜度值最大),那么艾洛不会移动甜甜圈,而是直接吃掉;
    请你求出艾洛吃完所有甜甜圈的最小移动步数
     
    输入
    3 3
    1 4 5
    2 7 3
    输出
    6

    首先拿到这道题目一开始的想法绝对是暴力,但是我们很容易发现暴力会被卡成n2(max1, maxn-1 ......  maxn-2, max2)就是将最大最小交替放置。

    考虑优化。我们真的需要知道所有元素的绝对顺序么?似乎是不必要的。我们只需要知道当前最大元素上面有多少个元素即可,以及判断这个最大元素是在左区间还是右区间。

    那么求出当前元素之前有多少个元素该如何求呢?考虑树状数组。树状数组可以在logn时间内求出当前元素之前有多少个元素,而且支持单点修改。非常适合这道题目。

    那么左右区间该如何个维护呢。我们稍微模拟一下这个过程可以发现,每次我们都会将当前最大的元素作为左右区间的分割点。那么我们只需要在每次算出贡献之后把区间的分割点修改即可。

    但是考虑到左右区间都是自顶向上,所以在存左区间时需要倒序存储。

    具体代码如下:

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 2e5+10;
    typedef long long ll;
    
    int n, m;
    int tree[maxn];
    
    int lowbit(int x) {
        return x & (-x);
    }
    
    void add(int pos, int val) {
        for (pos ; pos < maxn; pos += lowbit(pos)) {
            tree[pos] += val;
        }
    }
    
    int query(int pos) {
        int sum = 0;
        for (pos ; pos >= 1; pos -= lowbit(pos)) {
            sum += tree[pos];
        }
        return sum;
    }
    
    struct node {
        int val, id;
    } a[maxn];
    
    bool cmp(node a1, node a2) {
        return a1.val > a2.val;
    }
    
    int main() {
        scanf("%d%d", &n, &m);
        int cnt = 0;
        for (int i = n; i >= 1; -- i) {
            a[++ cnt].id = i;
            scanf("%d", &a[cnt].val);
        }
        for (int i = 1; i <= m; ++ i) {
            a[++cnt].id = i + n;
            scanf("%d", &a[cnt].val);
        }
        sort(a+1, a+1+cnt, cmp); ///大到小排序
        int bound = n; ///划分左右区间
        for (int i = 1; i <= cnt; ++ i) {
            add(i, 1);
        }
        ll ans = 0;
        for (int i = 1; i <= cnt; ++ i) {
            int p = a[i].id;
            if (p > bound) { ///右区间
                ans += query(p) - query(bound) - 1;
            }
            else { ///左区间
                ans += query(bound) - query(p);
            }
            add(p, -1);
            bound = p; ///修改分割点
        }
        printf("%lld
    ", ans);
        return 0;
    }
  • 相关阅读:
    HDU 5090 Game with Pearls
    HDU 1394 Minimum Inversion Number
    HDU 1698 Just a Hook
    POJ 2104 K-th Number
    UVA 1160
    HDU 5895 Mathematician QSC
    HDU 3294 Girls' research
    HDU 3068 最长回文
    PyCharm每日技巧-1
    如何一年考过日语一级
  • 原文地址:https://www.cnblogs.com/Vikyanite/p/14840672.html
Copyright © 2011-2022 走看看