• hdoj6701 Make Rounddog Happy(单调栈维护区间最大+分治)


    传送:http://acm.hdu.edu.cn/showproblem.php?pid=6701

    题意:

    给定一个长度为$n$的数组,问存在多少个子序列可以满足:$max(a_l,a_{l+1},...,a_r-(r-l+1)<=k$。同时要求子序列内数字不重复。

    数据范围:

    $1<=n<=3e5,1<=a_i<=n$。

    分析:

    首先考虑不重复怎么做呢?

    很容易想到用单调栈维护当前$a_i$作为最大值可以扩展到的左界和右界。$L[i],R[i]$。

    然后考虑怎么重复数字呢?然后就可以想到,一个数作为左界(右界)向右(左)不重复数字最长到达的位置。$L2[i],R2[i]$。

    然后分治考虑答案。对于每个$a_i$作为最大值,找边界!

    拿左侧或者右侧元素较少的一侧进行枚举。

    假设左侧元素更少:枚举左界,然后判断右界。同理去处理右界。

    然后对于每个情况累加答案即可。

    有一个证明复杂度的博客:https://blog.csdn.net/qq_41955236/article/details/99990149

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 typedef long long ll;
     4 const int maxn=3e5+10;
     5 int a[maxn],L[maxn],L2[maxn],R[maxn],R2[maxn],q[maxn],num[maxn],len[maxn];
     6 int main(){
     7 //    freopen("in.txt","r",stdin);
     8 //    freopen("out.txt","w",stdout);
     9     int t,n,k;scanf("%d",&t);
    10     while (t--){
    11         scanf("%d%d",&n,&k);
    12         for (int i=1;i<=n;i++) scanf("%d",&a[i]),len[i]=max(1,a[i]-k);
    13         int top=0;
    14         for (int i=1;i<=n;i++){
    15             while (top && a[q[top]]<a[i]) top--;
    16             if (top==0) L[i]=1; else L[i]=q[top]+1;
    17             q[++top]=i;
    18         }
    19         top=0;
    20         for (int i=n;i>=1;i--){
    21             while (top && a[q[top]]<a[i]) top--;
    22             if (top==0) R[i]=n; else R[i]=q[top]-1;
    23             q[++top]=i;
    24         }
    25         for (int i=1;i<=n;i++) num[i]=0;top=0;
    26         for (int i=1;i<=n;i++){
    27             while (top<n && num[a[top+1]]==0){
    28                 top++; num[a[top]]++;
    29             }
    30             L2[i]=top;
    31             num[a[i]]--;
    32         }
    33         for (int i=1;i<=n;i++) num[i]=0;top=n+1;
    34         for (int i=n;i>=1;i--){
    35             while (top>1 && num[a[top-1]]==0){
    36                 top--; num[a[top]]++;
    37             }
    38             R2[i]=top;
    39             num[a[i]]--;
    40         }
    41         ll ans=0;
    42         for (int i=1;i<=n;i++){
    43             if (i-L[i]+1<=R[i]-i+1){
    44                 for (int j=L[i];j<=i;j++){
    45                     if (L2[j]<i) continue;
    46                     int rr=min(L2[j],R[i]);//右界 
    47                     int nn=i-j+1; //a[i]左侧的长度
    48                     if (len[i]<=nn) ans+=rr-i+1;
    49                     else ans+=max(0,rr-a[i]+k-j+2); 
    50                 }
    51             }
    52             else{
    53                 for (int j=i;j<=R[i];j++){
    54                     if (R2[j]>i) continue;
    55                     int ll=max(R2[j],L[i]);//左界 
    56                     int mm=j-i+1; //a[i]右侧的长度
    57                     if (len[i]<=mm) ans+=i-ll+1;
    58                     else ans+=max(0,j+1-a[i]+k-ll+1);
    59                 }
    60             }
    61         }
    62         printf("%lld
    ",ans);
    63     }
    64     return 0;
    65 }
  • 相关阅读:
    sys模块详解
    os模块详解2
    tyvj 1203 机器分配
    洛谷 P1496 火烧赤壁
    P1204 [USACO1.2]挤牛奶Milking Cows
    bzoj 2120 数颜色
    P2056 采花
    P1972 [SDOI2009]HH的项链
    9.20模拟赛
    P2709 小B的询问
  • 原文地址:https://www.cnblogs.com/changer-qyz/p/11392174.html
Copyright © 2020-2023  润新知