题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5289
题意:给你n个数和k,求有多少的区间使得区间内部任意两个数的差值小于k,输出符合要求的区间个数
思路:求出区间的最大最小值,只要他们的差值小于k,那么这个区间就符合要求,但是由于n较大,用暴力一定超时,所以就要用别的方法了;而RMQ是可以求区间的最值的,而且预处理的复杂度只有O(nlogn),而查询只是O(1)处理,这样相对来说节约了时间,再根据右端点来二分枚举左端点(其实不用二分好像更快,估计是数据问题)。
而另一种方法不得不说,学了C++的一定要在认真的去看一下STL的那些用法,这次用multiset来做就大大的节约时间,而且又不用思考太多,只要从左到右模拟区间,就可以了。
(RMQ+二分)代码:
#include <cstdio> #include <cstdlib> #include <cmath> #include <cstring> #include <iostream> #include <queue> #include <algorithm> #include <vector> #include <set> using namespace std; #define LL __int64 #define INF 0x3f3f3f3f const int MAXN=100005; #define mod 1000000007 int a[MAXN]; LL ans; int dp1[MAXN][30],dp2[MAXN][30]; void init(int n) { for(int i=1;i<=n;i++) dp1[i][0]=dp2[i][0]=a[i]; for(int j=1;(1<<j)<=n;j++) { for(int i=1;i+(1<<j)-1<=n;i++) { dp1[i][j]=max(dp1[i][j-1],dp1[i+(1<<(j-1))][j-1]); dp2[i][j]=min(dp2[i][j-1],dp2[i+(1<<(j-1))][j-1]); } } } int RMQ(int L,int R) { int k=0; while((1<<(k+1))<=R-L+1)k++; return max(dp1[L][k],dp1[R-(1<<k)+1][k])-min(dp2[L][k],dp2[R-(1<<k)+1][k]); } int binarySearch(int L,int R,int n,int k) { int mid; int l=L,r=R; while(l<=r) { mid=(l+r)/2; if(RMQ(mid,R)>=k) { l=mid+1; } else { r=mid-1; } } if(RMQ(mid,R)>=k) mid++; return mid; } int main() { int T,i,j,n,k,mi,ma,l,r; while(~scanf("%d",&T)) { while(T--) { scanf("%d%d",&n,&k); for(i=1;i<=n;i++) scanf("%d",&a[i]); if(!k) { printf("0\n"); continue; } if(k==1) { printf("%d\n",n); continue; } init(n); ans=0; for(i=j=1;i<=n;i++) { j=binarySearch(j,i,n,k); ans+=i-j+1; } printf("%I64d\n",ans); } } return 0; }
(STL)代码:
#include <cstdio> #include <cstdlib> #include <cmath> #include <cstring> #include <iostream> #include <queue> #include <algorithm> #include <vector> #include <set> using namespace std; #define LL __int64 #define INF 0x3f3f3f3f const int MAXN=100005; #define mod 1000000007 int a[100005]; LL ans; int main() { int T,i,j,n,k,mi,ma,l,r; while(~scanf("%d",&T)) { while(T--) { scanf("%d%d",&n,&k); for(i=0;i<n;i++) scanf("%d",&a[i]); if(!k) { printf("0\n"); continue; } if(k==1) { printf("%d\n",n); continue; } l=0; r=1; multiset<int>s; s.insert(a[0]); ans=n; while(1) { if(s.size()) { mi=*s.begin(); ma=*s.rbegin(); if(abs(a[r]-mi)<k&&abs(a[r]-ma)<k) { ans+=s.size(); s.insert(a[r]); r++; if(r==n) break; } else { if(s.size()) s.erase(s.find(a[l])); l++; } } else { l=r; s.insert(a[r]); r++; if(r==n) break; } } printf("%I64d\n",ans); } } return 0; }