• 牛客网多校第5场 H subseq 【树状数组+离散化】


    题目:戳这里

    学习博客:戳这里

    题意:给n个数为a1~an,找到字典序第k小的序列,输出该序列所有数所在位置。

    解题思路:先把所有序列预处理出来,方法是设一个数组为dp,dp[i]表示以i为开头的序列共有多少个。这样当k>dp[i],则以i为开头的序列满足不了第k小,k-=dp[i],继续往后找,知道找到k<=dp[i],则把i记录在数组ans中,--k。--k的意思是去掉了我们所记录的ans这一条序列。此时若k==0,则说明已经找到答案,跳出循环输出即可,否则继续往下找,思路还算比较常规。

    那么dp数组具体怎么预处理呢?因为是求以i为开头的序列,所以类似于求后缀和,比如此时我们已经有了2 3 4,此时要插入数字1,则对1的贡献有sum[2]+sum[3]+sum[4],即1分别可以接在2,3,4前面或者只有一个1,也就是树状数组中,1的贡献=getsum(1 + 1) + 1。(getsum()为后缀和) 

    这里注意两个坑点:一个是a1~an范围很大,必须要离散化。二是求和有可能会爆long long (这个是真的坑,所以当大于1e18的时候,令其等于1e18就行,因为k最大就是1e18嘛。

    附本人ac代码:

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 typedef long long ll;
     4 const ll maxn = 5e6 + 10;
     5 const ll inf = 1e18;
     6 ll a[maxn], c[maxn], dp[maxn], b[maxn], d[maxn];
     7 ll ans[maxn];
     8 ll n, k;
     9 
    10 ll lowbit(ll x)
    11 {
    12     return x&-x;
    13 }
    14 ll gsum(ll x)
    15 {
    16     ll ans = 0;
    17     while(x <= n)
    18     {
    19         ans += c[x];
    20         if(ans > inf) ans = inf;
    21         x += lowbit(x);
    22     }
    23     return ans;
    24 }
    25 void updat(ll x, ll y)
    26 {
    27     while(x)
    28     {
    29         c[x] += y;
    30         if(c[x] > inf) c[x] = inf;
    31         x -= lowbit(x);
    32     }
    33 }
    34 int main()
    35 {
    36 
    37     scanf("%lld %lld", &n, &k);
    38     for(ll i = 1; i <= n; ++i)
    39     {
    40         scanf("%lld", &d[i]);
    41         a[i] = d[i];
    42     }
    43     sort(a + 1, a + 1 + n);
    44     for(ll i  = 1; i <= n; ++i)//离散化
    45     {
    46         b[i] = lower_bound(a + 1, a + 1 + n, d[i]) - a;
    47     }
    48     dp[n] = 1;
    49     updat(b[n], 1);
    50     for(ll u  = n - 1; u >= 1; --u)
    51     {
    52         dp[u] = gsum(b[u] + 1) + 1;//这一步容易写错,之前我没想到会有多个相同的数,所以一直写的是gsum(b[u])+1,wa到死。主要还是离散化用的生疏
    53         updat(b[u], dp[u]);
    54     }
    55     int len = 0;
    56     for(ll i = 1; i <= n; ++i)
    57     {
    58         if(b[i] > b[ans[len]])//这里同上,b[i]可能会等于b[ans[len]],所以要判断一下
    59         {
    60             if(k > dp[i]) k -= dp[i];
    61             else
    62             {
    63                 --k;
    64                 ans[++len] = i;
    65             }
    66         }
    67         if(!k) break;
    68     }
    69     if(len == 0 || k)
    70     {
    71         puts("-1");
    72         return 0;
    73     }
    74     printf("%d
    ", len);
    75     for(int i = 1; i <= len; ++i)
    76     {
    77         if(i > 1)
    78         printf(" ");
    79         printf("%lld", ans[i]);
    80     }
    81     printf("
    ");
    82     return 0;
    83 }
    View Code
  • 相关阅读:
    当虚拟空间(主机)不支持301时,该怎样重定向域名
    总结高权重论坛
    一个错
    layui树形框架
    命令模式
    《编写有效用例》读书笔记2
    jieba安装与简单使用
    list正序倒序排列
    每日博客
    每日博客
  • 原文地址:https://www.cnblogs.com/zmin/p/9523503.html
Copyright © 2020-2023  润新知