HDU-5806 NanoApe Loves Sequence Ⅱ(two-pointer或二分)

题目大意:给一个整数序列,统计<k,m>子序列的数目。<k,m>序列是满足第k大的数字不比m小的连续子序列。

题目分析:维护一个不小于m的数的个数的后缀和数组,可以枚举序列起点,二分查找右端点序列最近的一个<k,m>序列。因为最近右端点是不减的,所以也可以用two-pointer在O(n)的时间复杂度内得到结果。

代码如下:

使用二分查找:

# include<iostream>
# include<cstdio>
# include<string>
# include<cmath>
# include<cstring>
# include<algorithm>
using namespace std;
# define LL long long
# define mid (l+(r-l)/2)

const int N=200000;

int a[N+5];
int sum[N+5];

int f(int l,int r,int val)
{
    while(l<r){
        if(sum[mid]>val) l=mid+1;
        else r=mid;
    }
    return l;
}

int main()
{
    int T,n,m,k;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d%d",&n,&m,&k);
        for(int i=0;i<n;++i) scanf("%d",a+i);
        sum[n]=0;
        for(int i=n-1;i>=0;--i){
            if(a[i]>=m) sum[i]=sum[i+1]+1;
            else sum[i]=sum[i+1];
        }
        LL ans=0;
        for(int i=0;i+k-1<n;++i){
            int id=f(i+k-1,n,sum[i]-k);
            if(sum[i]-sum[id]>=k) ans+=n-id+1;
        }
        cout<<ans<<endl;
    }
    return 0;
}

  

使用two-pointer:

# include<cstdio>
# include<iostream>
# include<algorithm>
using namespace std;
# define LL long long

const int N=200000;

int a[N+5];

int main()
{
    int T,n,m,k;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d%d",&n,&m,&k);
        for(int i=0;i<n;++i)
            scanf("%d",a+i);
        int p=0;
        int cnt=0;
        LL ans=0;
        for(int i=0;i+k-1<n;++i){
            while(cnt<k&&p<n){
                if(a[p]>=m) ++cnt;
                ++p;
            }
            if(cnt>=k) ans+=(LL)(n-p+1);
            if(a[i]>=m) --cnt;
        }
        printf("%lld
",ans);
    }
    return 0;
}

  

原文地址:https://www.cnblogs.com/20143605--pcx/p/5746670.html