zoukankan      html  css  js  c++  java
  • cf1208 D Restore Permutation (二分+树状数组)

    题意

    让你构造一个长度为n的序列,记为p1……pn,(这个序列是1~n的全排列的一种)

    给你n个数,记为s1……sn,si的值为p1……pi-1中小于pi的数的和。

    思路

    显然,应该倒着来,也就是从p开始构造,这样的话,当要填p的时候,p1到pi-1就是所有的还未填的数,那么我们只需要去找哪个前缀和符合就可以了。

    比如:现在还没填进去的数是 1,2,3,4,5

    而我现在的si 是6,那么,对应的pi 就是4,因为这样无论1,2,3,5怎么排,都符合si 为6

    (才学疏浅,不怎么会讲)

    那么,选完要删除,所以要修改前缀和,考虑用树状数组,查找哪个符合,自然是二分。

    代码

    #include <stdio.h>
    #include <queue>
    #include <string>
    #include <string.h>
    #include <algorithm>
    #include <math.h>
    #include <set>
    using namespace std;
    typedef long long int ll;
    const int maxn = 2e5 + 10;
    const int inf = 70000000;
    const ll mod = 998244353;
    const ll seed = 131;
    ll s[maxn],c[maxn],ans[maxn],n;
    int lowbit(int x)
    {
        return x & (-x);
    }
    void insert(ll x,int i)
    {
        while(i <= n){
            c[i] += x;
            i += lowbit(i);
        }
    }
    ll getsum(int i)
    {
        ll sum = 0;
        while(i > 0){
            sum += c[i];
            i -= lowbit(i);
        }
        return sum;
    }
    int vis[maxn];
    int query(ll x)
    {
        int l,r,mid;
        ll res;
        l = 0;r = n;
        while(l <= r){
            mid = (l + r) >> 1;
            res = getsum(mid);
            if(res == x){
                if(vis[mid + 1])
                    l = mid + 1;
                else
                    return mid;
            }
            else if(res < x){
                l = mid + 1;
            }
            else{
                r = mid - 1;
            }
        }
    }
    int main()
    {
        while(scanf("%d",&n) != EOF){
            memset(vis,0,sizeof(vis));
            memset(c,0,sizeof(c));
            for(int i = 1;i <= n;i++){
                scanf("%lld",&s[i]);
                insert(i,i);
            }
    
            for(int i = n;i >= 1;i--){
                ans[i] = query(s[i]) + 1;
                vis[ans[i]] = 1;
                insert(-ans[i],ans[i]);
            }
            for(int i = 1;i <= n;i++)
                printf("%d ",ans[i]);
            puts("");
        }
        return 0;
    }
  • 相关阅读:
    关于HashMap的线程安全问题
    Java利器之UML类图详解
    mongoDB4.0数据库
    requests-html库render的使用
    爬虫最新的库requests-html库总结
    爬虫多次爬取时候cookie的存储用于登入
    requests模块响应体属性和方法重新整理
    Visual Studio 代码补全功能有时候会失效的原因
    C++Primer笔记——文本查询程序(原创,未使用类)
    Clion 常用快捷键
  • 原文地址:https://www.cnblogs.com/InitRain/p/12329447.html
Copyright © 2011-2022 走看看