HDU 5289——Assignment——————【RMQ+优化求解】

Assignment

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 902    Accepted Submission(s): 441


Problem Description
Tom owns a company and he is the boss. There are n staffs which are numbered from 1 to n in this company, and every staff has a ability. Now, Tom is going to assign a special task to some staffs who were in the same group. In a group, the difference of the ability of any two staff is less than k, and their numbers are continuous. Tom want to know the number of groups like this.
 

 

Input
In the first line a number T indicates the number of test cases. Then for each case the first line contain 2 numbers n, k (1<=n<=100000, 0<k<=10^9),indicate the company has n persons, k means the maximum difference between abilities of staff in a group is less than k. The second line contains n integers:a[1],a[2],…,a[n](0<=a[i]<=10^9),indicate the i-th staff’s ability.
 

 

Output
For each test,output the number of groups.
 

 

Sample Input
2 4 2 3 1 2 4 10 5 0 3 4 5 2 1 6 7 8 9
 

 

Sample Output
5 28
Hint
First Sample, the satisfied groups include:[1,1]、[2,2]、[3,3]、[4,4] 、[2,3]
 

 

题目大意:给你t组测试数据。每组有n,k。表示有序列长度为n,求有多少个连续的区间满足区间内的任意元素之差小于k。
解题思路:现在用i,j分别表示左右区间位置。然后从左往右扩展,如果要扩展的那个元素跟区间内的任意元素差值都小于k,则res++,且区间向右扩展一个长度。直到遇到元素Aj,跟区间内的某个元素发生冲突,那么我停止向右扩展这个Aj。然后我让原来的区间[i,j-1]左区间向右移动一个位置。我向右移动左区间,那么这个区间内的符合的区间个数必然比刚才的[i,j-1]这个区间少一个,那么res--。然后这时候继续扩展上次发生冲突的位置j,看现在的区间是否能跟Aj不发生冲突。然后一直重复地操作。简单总结就是如果右区间能扩展,就扩展;不能扩展,让左区间向右移动一个位置,然后看现在的区间能不能让右区间向右扩展。
 
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define INT long long
const int maxn=1e5+20;
int d[maxn][50];
int dp[maxn][50];
int A[maxn];
int Abs(int x){
    return x<0? -x:x;
}
void RMQ_init(int n){//RMQ维护出区间i,j之间的最大最小值。
    for(int i=0;i<n;i++){
        d[i][0]=A[i];
        dp[i][0]=A[i];
    }
    for(int j=1;(1<<j)<=n;j++){
        for(int i=0;i+(1<<j)-1<n;i++){
            d[i][j]=min(d[i][j-1],d[i+(1<<(j-1))][j-1]);
            dp[i][j]=max(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);
        }
    }
}
int RMQ(int L,int R,int typ){
    int k=0;
    while((1<<(k+1)<=R-L+1))
          k++;
    if(typ==0)
        return min(d[L][k],d[R-(1<<k)+1][k]);
    else
        return max(dp[L][k],dp[R-(1<<k)+1][k]);
}
int main(){
    int t,i,j,k,n,tmp,ret,itvlav,itvliv,sum,flag;
    INT res,ans;
    scanf("%d",&t);
    while(t--){
        memset(dp,0,sizeof(dp));
        memset(d,0,sizeof(d));
        memset(A,0,sizeof(A));
        scanf("%d%d",&n,&k);
        for(i=0;i<n;i++){
            scanf("%d",&A[i]);
        }
        RMQ_init(n);
        tmp=0,res=0,sum=0;
        itvlav=itvliv=A[0];
        for(i=0;i<n;i++){
            flag=0;
            for(j=tmp;j<n;j++){
                if(Abs(itvlav-A[j])<k&&Abs(itvliv-A[j])<k){//右区间能向右扩展
                    tmp=j+1;
                    itvlav=RMQ(i,j,1);
                    itvliv=RMQ(i,j,0);
                    res++;
                }else{  //右区间现在无法扩展,向右移动左区间位置,看新的区间是否能向右扩展
                    flag=1;
                    tmp=j;
                    itvlav=RMQ(i+1,j-1,1);
                    itvliv=RMQ(i+1,j-1,0);
                    break;
                }
            }
            sum+=res;
            res--;
            if(flag==1){
                 if(res==0){
                    itvlav=itvliv=A[tmp];
                 }
            }


        }
        printf("%lld\n",sum);
    }
    return 0;
}

  

 

posted @ 2015-07-22 14:36  tcgoshawk  阅读(196)  评论(0编辑  收藏  举报