• 题解 CF1208D 【Restore Permutation】


    (Large exttt {CF1208D})

    思路:手玩,树状数组,线段树

    这道题的思路就是先自己手玩数据,可以逐渐发现方法,思维难度不高。


    (large exttt{Meaning})

    有一个长度为 (n) ,各个数字值域为 ([1,n]) 的全排列序列 (a) ,给出序列 (b)(b_i=sum_{j=1}^{i-1}a_j imes[a_j<a_i]),请求出序列 (a)。(保证有解)


    (large exttt{Solution})

    第一种方法:

    乍一看好像毫无头绪,可以先观察下面的数据

    a={5,2,3,4,1,6}
    
    b={0,0,2,5,0,15}
    

    容易发现, (b) 序列最后一个 (0) 的位置 (a) 序列对应的位置就是 (1) ,因为没有一个数小于 (1) ,并且除 (1) 外所有数都大于 (1) (只能是 (b) 序列中最后一个 (0) )。

    找到了 (1) ,我们先将在 (b) 序列的这个位置后面的贡献减去 (1)

    就可以进一步推出 (2) 的位置,然后你会惊喜地发现找 (2) 的方法和 (1) 一样。

    注意下细节:找到最后一个 (0) 后,要将 (b) 的这一位的数赋为 (-1)

    这样用线段树维护就能搞定这道题。


    第二种方法:

    对于一开始 (a) 序列最后一个数 (x)(b) 最后一个数的值必为 ((1+x) imes x/2)

    但是对于 (x) 之前的数 (y) ,它有可能大于 (x) ,这使得 (b) 这个位置上的值不是 ((y+1) imes y/2) ,少了一个 (x)

    从后往前推,并边找边用数据结构改。

    可以发现可以用树状数组维护上述的 ((y+1) imes y/2-sum x~~~(x<y))
    。(即区间修改 (x) ,单点查询)。

    找的时候在外面套一个二分查询就行了。


    (large exttt{Code})

    第二种方法的代码(第一种没写QwQ)

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N = 2e6;
    inline int read()
    {
        register int s = 0;
        register bool neg = 0;
        register char c = getchar();
        for (; c < '0' || c > '9'; c = getchar())
            neg |= (c == '-');
        for (; c >= '0' && c <= '9'; s = s * 10 + (c ^ 48), c = getchar())
            ;
        return (neg ? -s : s);
    }
    
    int a, l, r, s[N + 10], p[N + 10], ans[N + 10];
    
    inline void insert(int n, int m)
    {
        while (n <= a)
        {
            p[n] += m;
            n += n & -n;
        }
    }
    
    inline int query(int n)
    {
        int m = 0;
        while (n)
        {
            m += p[n];
            n -= n & -n;
        }
        return m;
    }
    
    signed main()
    {
        a = read();
        for (int i = 1; i <= a; i++)
            s[i] = read(), insert(i, i);
        for (int i = a; i >= 1; i--)
        {
            int l = 1, r = a, mid, sum = 0;
            while (l <= r)
            {
                mid = (l + r) >> 1;
                if (query(mid - 1) <= s[i])
                    sum = mid, l = mid + 1;
                else
                    r = mid - 1;
            }
            insert(sum, -sum);
            ans[i] = sum;
        }
        for (int i = 1; i <= a; i++)
            printf("%lld ", ans[i]);
        return 0;
    }
    
  • 相关阅读:
    【转】python:让源码更安全之将py编译成so
    [转]Ubuntu python-config
    【转】动态复权(真实价格)模式原理详解!
    [转]Aroon Indicator
    LeetCode 852. Peak Index in a Mountain Array
    LeetCode 1257. Smallest Common Region
    LeetCode 1034. Coloring A Border
    LeetCode 348. Design Tic-Tac-Toe
    LeetCode 452. Minimum Number of Arrows to Burst Balloons
    LeetCode 733. Flood Fill
  • 原文地址:https://www.cnblogs.com/RedreamMer/p/13620860.html
Copyright © 2020-2023  润新知