「hdu6701」Make Rounddog Happy【dp+RMQ+分治】

5 篇文章 0 订阅
4 篇文章 0 订阅

Make Rounddog Happy

Time Limit: 2000/2000 MS (Java/Others) Memory Limit: 524288/524288 K (Java/Others)
Total Submission(s): 242 Accepted Submission(s): 70

Problem Description

R o u n d d o g Rounddog Rounddog always has an array a 1 , a 2 , ⋯ , a n a_1,a_2,⋯,a_n a1,a2,,an in his right pocket, satisfying 1 ≤ a i ≤ n 1\leq a_i\leq n 1ain.

A subarray is a non-empty subsegment of the original array. R o u n d d o g Rounddog Rounddog defines a good subarray as a subsegment a l , a l + 1 , ⋯ , a r a_l,a_{l+1},⋯,a_r al,al+1,,ar that all elements in it are different and m a x ( a l , a l + 1 , … , a r ) − ( r − l + 1 ) ≤ k max(a_l,a_{l+1},…,a_r)−(r−l+1)\leq k max(al,al+1,,ar)(rl+1)k.

R o u n d d o g Rounddog Rounddog is not happy today. As his best friend, you want to find all good subarrays of a to make him happy. In this case, please calculate the total number of good subarrays of a a a.

Input

The input contains several test cases, and the first line contains a single integer T ( 1 ≤ T ≤ 20 ) T (1\leq T\leq 20) T(1T20), the number of test cases.

The first line of each test case contains two integers n ( 1 ≤ n ≤ 300000 ) n (1\leq n\leq 300000) n(1n300000) and k ( 1 ≤ k ≤ 300000 ) k (1\leq k\leq 300000) k(1k300000).

The second line contains n integers, the i-th of which is ai ( 1 ≤ a i ≤ n ) (1\leq a_i\leq n) (1ain).

It is guaranteed that the sum of n over all test cases never exceeds 1000000 1000000 1000000.

Output

One integer for each test case, representing the number of subarrays R o u n d d o g Rounddog Rounddog likes.

Sample Input

2
5 3
2 3 2 2 5
10 4
1 5 4 3 6 2 10 8 4 5

Sample Output

7
31

Source

2019 Multi-University Training Contest 10

题意

  • 给一个数组,求有多少个子区间 [ l , r ] [l,r] [l,r],使得 m a x ( a l , a l + 1 , … , a r ) − ( r − l + 1 ) ≤ k max(a_l,a_{l+1},…,a_r)−(r−l+1)\leq k max(al,al+1,,ar)(rl+1)k [ l , r ] [l,r] [l,r]内的数互不相同

题解

  • R M Q RMQ RMQ+分治套路题
  • 就是预处理 R M Q RMQ RMQ,并且预处理以每一个位置为区间左端点的最右右端点使得区间内的数两两不相同,以及以每一个位置为右端点的最左左端点使得区间内的数两两不相同,然后分治处理就行了,每次枚举一个较小的子区间进行合并,这样期望复杂度是 O ( n log ⁡ n ) O(n \log n) O(nlogn)的,和上次牛客出的2019牛客第三场G基本差不多

代码

#include<bits/stdc++.h>

using namespace std;
const int maxn=3e5+10;
#define inf 0x3f3f3f3f

namespace IO{ 
    #define BUF_SIZE 100000 
    #define OUT_SIZE 100000 

    bool IOerror=0; 
    inline char nc(){ 
        static char buf[BUF_SIZE],*p1=buf+BUF_SIZE,*pend=buf+BUF_SIZE; 
        if (p1==pend){ 
            p1=buf; pend=buf+fread(buf,1,BUF_SIZE,stdin); 
            if (pend==p1){IOerror=1;return -1;} 
        } 
        return *p1++; 
    } 
    inline bool blank(char ch){return ch==' '||ch=='\n'||ch=='\r'||ch=='\t';} 
    inline bool read(double &x){ 
        bool sign=0; char ch=nc(); x=0; 
        for (;blank(ch);ch=nc()); 
        if (IOerror) return false; 
        if (ch=='-')sign=1,ch=nc(); 
        for (;ch>='0'&&ch<='9';ch=nc())x=x*10+ch-'0'; 
        if (ch=='.'){ 
            double tmp=1; ch=nc(); 
            for (;ch>='0'&&ch<='9';ch=nc())tmp/=10.0,x+=tmp*(ch-'0'); 
        } 
        if (sign)x=-x; return true;
    } 
    template<typename T>
    inline bool read(T &x){ 
        bool sign=0; char ch=nc(); x=0; 
        for (;blank(ch);ch=nc()); 
        if (IOerror) return false; 
        if (ch=='-')sign=1,ch=nc(); 
        for (;ch>='0'&&ch<='9';ch=nc())x=x*10+ch-'0'; 
        if (sign)x=-x; return true;
    } 
    inline bool read(char *s){ 
        char ch=nc(); 
        for (;blank(ch);ch=nc()); 
        if (IOerror) return false; 
        for (;!blank(ch)&&!IOerror;ch=nc())*s++=ch; 
        *s=0; return true;
    } 
};
using namespace IO;

int dpr[maxn],dpl[maxn],cnt[maxn],k;

//st
int n,a[maxn],dp[maxn][20],p[maxn][20],Log[maxn];

void init_st()
{
    Log[0]=-1;for(int i=1;i<=n;i++) Log[i]=Log[i>>1]+1; 
    for(int i=1;i<=n;i++) dp[i][0]=a[i],p[i][0]=i;
    for(int j=1;(1<<j)<=n;j++) for(int i=1;i+(1<<j)-1<=n;i++) {
        dp[i][j]=max(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);
        if(dp[i][j-1]>=dp[i+(1<<(j-1))][j-1]) p[i][j]=p[i][j-1];
        else p[i][j]=p[i+(1<<(j-1))][j-1];
    }
}

int query(int l,int r)
{
    int k=Log[r-l+1];
    if(dp[l][k]>=dp[r-(1<<k)+1][k]) return p[l][k];
    return p[r-(1<<k)+1][k];
}



void init_()
{
    for(int i=1;i<=n;i++) cnt[i]=0;
}

long long solve(long long l,long long r)
{
    if(r<l) return 0;
    return r-l+1;
}

long long get(long long t)
{
    return t<=0?1:t;
}

int tot=0;
long long dfs(int l,int r)
{
    if(l==r) return a[l]-k<=1;
    if(l>r) return 0;
    int pos=query(l,r);
    long long res=0;
    if(pos-l<r-pos) {
        for(int i=l;i<=pos;i++) {
            res+=solve(max(1LL*pos,i+get(a[pos]-k)-1),min(r,dpr[i]));
        }
    }else {
        for(int i=pos;i<=r;i++) {
            res+=solve(max(l,dpl[i]),min(1LL*pos,i-get(a[pos]-k)+1));
        }
    }
    return res+dfs(l,pos-1)+dfs(pos+1,r);
}

int main()
{
    //freopen("/Users/wzw/Desktop/ACM/1.in","r",stdin);
    int t;read(t);
    while(t--) {
        read(n);read(k);
        for(int i=1;i<=n;i++) read(a[i]);
        init_st();

        init_();
        dpr[n+1]=n;
        for(int i=n;i>=1;i--) {
            if(cnt[a[i]]) {
                dpr[i]=cnt[a[i]]-1;
                cnt[a[i]]=i;
            }else {
                cnt[a[i]]=i;
                dpr[i]=n;
            }
            dpr[i]=min(dpr[i],dpr[i+1]);
        }

        init_();
        for(int i=1;i<=n;i++) {
            if(cnt[a[i]]) {
                dpl[i]=cnt[a[i]]+1;
                cnt[a[i]]=i;
            } else {
                cnt[a[i]]=i;
                dpl[i]=1;
            }
            dpl[i]=max(dpl[i],dpl[i-1]);
        }

        printf("%lld\n",dfs(1,n));
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值