• Educational Codeforces Round 65 (Rated for Div. 2) E. Range Deleting(思维+coding)


    传送门

    参考资料:

      [1]:https://blog.csdn.net/weixin_43262291/article/details/90271693

    题意:

      给你一个包含 n 个数的序列 a,并且 max{ai} ≤ x;

      定义一个操作 f(L,R) 将序列 a 中  L ≤ ai ≤ R 的数删除;

      问有多少对满足条件的 (L,R) 使得执行完 f(L,R) 操作后的序列非递减;

    题解:

      [1]博文看了一晚上,终于理解了;

      枚举左区间 i,找到符合条件的最小的右区间 ki,f(1,k1),f(2,k2),....,f(x,kx);

      如果执行完 f(1,k1) 后序列非递减,那么执行完 f(1,k1+1),f(1,k1+2),....,f(1,x) 后同样会使得序列非递减;

      f(i,ki)同理,那么最终答案就是 (x-k1+1)+(x-k2+1)+......+(x-kx+1);

      如何高效的求解k1,k2,....,kx呢?

      首先看看相关变量解释:

    int n,x;///max{a[i]} <= x
    int a[maxn];
    int l[maxn];///l[i]:数字i第一次出现的位置
    int r[maxn];///r[i]:数字i最后一次出现的位置
    int L[maxn];///L[i]:数字[i,n]最先出现的位置
    int R[maxn];///R[i]:数字[1,i]最后出现的位置

      预处理出l,r,L,R数组:

     1 mem(l,INF);
     2 mem(r,0);
     3 for(int i=1;i <= n;++i)
     4 {
     5     l[a[i]]=min(i,l[a[i]]);
     6     r[a[i]]=i;
     7 }
     8 mem(L,INF);
     9 mem(R,0);
    10 for(int i=x;i >= 1;--i)
    11     L[i]=min(L[i+1],l[i]);
    12 for(int i=1;i <= x;++i)
    13     R[i]=max(R[i-1],r[i]);

      明确一点,k1 ≤ k2 ≤ ...... ≤ kx

      那么,首先求出 k1,然后,递推出 ki

      如何求解k1呢?

      上述查找可转化为找最小的 k1 使得 [k1+1,x] 组成的序列非递减;

    int k=x;///如果[k,x]非递减,那么k-1找下一个位置
    for(;k > 1 && r[k] <= L[k+1];--k);

      如何根据 k1 递推出 ki 呢?

    for(int i=2;i <= x && R[i-2] <= l[i-1];++i)
        for(;k < i || R[i-1] > L[k+1];++k);///找到第一个使得R[i-1]>=L[k+1]的k

    AC代码:

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define mem(a,b) memset(a,b,sizeof(a))
     4 #define ll long long
     5 #define INF 0x3f3f3f3f
     6 const int maxn=1e6+50;
     7 
     8 int n,x;///max{a[i]} <= x
     9 int a[maxn];
    10 int l[maxn];///l[i]:数字i第一次出现的位置
    11 int r[maxn];///r[i]:数字i最后一次出现的位置
    12 int L[maxn];///L[i]:数字[i,n]最先出现的位置
    13 int R[maxn];///R[i]:数字[1,i]最后出现的位置
    14 
    15 ll Solve()
    16 {
    17     mem(l,INF);
    18     mem(r,0);
    19     for(int i=1;i <= n;++i)
    20     {
    21         l[a[i]]=min(i,l[a[i]]);
    22         r[a[i]]=i;
    23     }
    24     mem(L,INF);
    25     mem(R,0);
    26     for(int i=x;i >= 1;--i)
    27         L[i]=min(L[i+1],l[i]);
    28     for(int i=1;i <= x;++i)
    29         R[i]=max(R[i-1],r[i]);
    30 
    31 
    32     int k=x;///如果[k,x]非递减,那么k-1找下一个位置
    33     for(;k > 1 && r[k] <= L[k+1];--k);
    34 
    35     ll ans=x-k+1;
    36     
    37     ///要确保[1,i-1]非递减
    38     ///且已知[k+1,x]非递减
    39     for(int i=2;i <= x && R[i-2] <= l[i-1];++i)
    40     {
    41         for(;k < i || R[i-1] > L[k+1];++k);///找到第一个使得R[i-1]>=L[k+1]的k
    42         
    43         ans += x-k+1;
    44     }
    45     return ans;
    46 }
    47 int main()
    48 {
    49 //    freopen("C:\Users\hyacinthLJP\Desktop\in&&out\contest","r",stdin);
    50     scanf("%d%d",&n,&x);
    51     for(int i=1;i <= n;++i)
    52         scanf("%d",a+i);
    53 
    54     printf("%lld
    ",Solve());
    55     return 0;
    56 }
    View Code
  • 相关阅读:
    Hugo搭建的博客删除文章事宜
    [GIT] Git学习笔记
    VS Code: 解决安装code-runner扩展run后无法在只读编辑器下编辑
    c/c++结构体总结
    恢复U盘做启动盘后的容量
    Manjaro安装Mysql
    win10环境下安装manjaro kde(双系统)
    IDEA设置编辑区主题
    IDEA设置主体、窗体及菜单的字体大小
    IDEA设置项目文件编码
  • 原文地址:https://www.cnblogs.com/violet-acmer/p/10908926.html
Copyright © 2020-2023  润新知