• ACM学习历程—HDU5592 ZYB's Premutation(逆序数 && 树状数组 && 二分)(BestCoder Round #65 1003)


    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5592

    题目大意就是给了每个[1, i]区间逆序对的个数,要求复原原序列。

    比赛的时候2B了一发。

    首先既然给了[1, i-1][1, i]区间逆序对的个数,自然可以求出与i组成逆序对的个数,自然就是i前面比i大的个数,自然也就能求出i前面比i小的个数。

    然后我考虑最后一个数,由于它在最后一个,所以所有数都在它前面,自然如果知道它前面有多少个比他小的,就知道它是几了。不妨设最后一个是p,然后考虑倒数第二个,如果它前面有x个比他小的,那么倒数第二个自然是除掉p以外排在x+1位置上的那个数。以此类推。

    有了这个需要数据结构的支持,可以用树状数组维护[1, n]区间1的个数,然后一旦找到某个数,就让它置0。然后找当前位置前面有x个数比他小,即在树状数组中前缀和为x+1的那个区间右值,此处我采用了二分查找。

    代码:

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cmath>
    #include <cstring>
    #include <algorithm>
    #include <set>
    #include <map>
    #include <queue>
    #include <string>
    #define LL long long
    
    using namespace std;
    
    const int maxN = 50005;
    int n, ans[maxN];
    int a[maxN];
    int d[maxN];
    
    int lowbit(int x)
    {
        return x&(-x);
    }
    
    void add(int id, int pls)
    {
        while(id <= maxN)//id×î´óÊÇmaxN
        {
            d[id] += pls;
            id += lowbit(id);
        }
    }
    
    int sum(int to)
    {
        int s = 0;
        while(to > 0)
        {
            s = s + d[to];
            to -= lowbit(to);
        }
        return s;
    }
    
    void input()
    {
        memset(d, 0, sizeof(d));
        scanf("%d", &n);
        int pre, now;
        pre = 0;
        for (int i = 1; i <= n; ++i)
        {
            scanf("%d", &now);
            a[i] = i-1-(now-pre);
            pre = now;
        }
    }
    
    int cal(int k)
    {
        int lt = 1, rt = n, mid, t;
        while (lt+1 < rt)
        {
            mid = (lt+rt)>>1;
            t = sum(mid);
            if (t >= k) rt = mid;
            else lt = mid;
        }
        if (sum(lt) == k) return lt;
        else return rt;
    }
    
    void work()
    {
        for (int i = 1; i <= n; ++i)
            add(i, 1);
        for (int i = n; i > 0; --i)
        {
            ans[i] = cal(a[i]+1);
            add(ans[i], -1);
        }
        for (int i = 1; i <= n; ++i)
        {
            if (i != 1) printf(" ");
            printf("%d", ans[i]);
        }
        printf("
    ");
    }
    
    int main()
    {
        //freopen("test.in", "r", stdin);
        int T;
        scanf("%d", &T);
        for (int times = 1; times <= T; ++times)
        {
            input();
            work();
        }
        return 0;
    }
    View Code
  • 相关阅读:
    [HihoCoder1259]A Math Problem
    [POJ1205]Water Treatment Plants
    [HDU5492]Find a path
    [USACO08JAN]Cell Phone Network
    [CodeForces-543D]Road Improvement
    [HAOI2012]外星人
    [CodeForces-869C]The Intriguing Obsession
    [CodeChef-CAPTCITI]Snakes capturing the Mongoose Cities
    CF741D Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths
    Luogu P4095 [HEOI2013]Eden的新背包问题
  • 原文地址:https://www.cnblogs.com/andyqsmart/p/5022433.html
Copyright © 2020-2023  润新知