HDU 5289 2015 Multi-University Training Contest 1 1002 RMQ+二分

本文介绍了一个算法问题,涉及到数组、区间查找和二分搜索技术,目的是找出数组中所有满足差值小于给定阈值K的连续子数组的数量。通过使用ST算法(线段树)和二分查找,可以高效地解决这个问题。

                  Assignment

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


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]
 

 

Author
FZUACM
 

 

Source

 

 

 

题意:

给出一个序列,求这个序列里面有多少组,满足组内的最大值-最小值<K

 

刚开始的想法

设dp[i]表示以i为左端点,最远可以到达的位置,使得区间[i,i],[i,i+1],,,[i,dp[i]]都满足条件

则以i为左端点有dp[i]-i+1个区间满足条件,再对所有的i,累加dp[i]-i+1,即为答案

 

问题是:递推不出dp[i]

 

后来看了题解,可以用rmq+二分求出i最远可以到达的位置,而不是递推。

 

先用st算法求出任意区间的最大值和最小值的差。

 

枚举左端点i,二分右端点j,则以i为左端点有j-i+1个区间满足。

累加,即为答案。

 

注意:最后答案要用long long

 

 

 1 #include<cstdio>
 2 #include<cstring>
 3 
 4 #define MAX(x,y) x>y?x:y;
 5 #define MIN(x,y) x<y?x:y;
 6 #define LL long long
 7 
 8 using namespace std;
 9 
10 const int MAXN=100000+10;
11 int a[MAXN];
12 int min[MAXN][20];
13 int max[MAXN][20];
14 
15 void init(int N)
16 {
17     for(int i=1;i<=N;i++)
18     {
19         min[i][0]=a[i];
20         max[i][0]=a[i];
21     }
22     for(int j=1;(1<<j)<=N;j++)
23     {
24         for(int i=1;(i+(1<<j)-1)<=N;i++)
25         {
26             min[i][j]=MIN(min[i][j-1],min[i+(1<<(j-1))][j-1]);
27             max[i][j]=MAX(max[i][j-1],max[i+(1<<(j-1))][j-1]);
28         }
29     }
30 }
31 
32 int query(int l,int r)
33 {
34     int k=0;
35     while((1<<(k+1))<=r-l+1)
36         k++;
37     int x=MAX(max[l][k],max[r-(1<<k)+1][k]);
38     int y=MIN(min[l][k],min[r-(1<<k)+1][k]);
39     return x-y;
40 }
41 
42 LL solve(int N,int K)
43 {
44     LL res=0;
45     for(int i=1;i<=N;i++)
46     {
47         int l=i,r=N;
48         while(r-l>1)
49         {
50             int p=(l+r)>>1;
51             if(query(i,p)<K)
52                 l=p;
53             else
54                 r=p;
55         }
56         if(query(i,r)<K)
57             res+=(LL)(r-i+1);
58         else
59             res+=(LL)(l-i+1);
60     }
61     return res;
62 }
63 
64 int main()
65 {
66     int test;
67     scanf("%d",&test);
68     while(test--)
69     {
70         int N,K;
71         scanf("%d%d",&N,&K);
72         for(int i=1;i<=N;i++)
73         {
74             scanf("%d",&a[i]);
75         }
76         init(N);
77 
78         printf("%I64d\n",solve(N,K));
79     }
80     return 0;
81 }
View Code

 

转载于:https://www.cnblogs.com/-maybe/p/4675693.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值