hdu 5289 Assignment(2015多校第一场第2题)RMQ+二分(或者multiset模拟过程)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5289
题意:给你n个数和k,求有多少的区间使得区间内部任意两个数的差值小于k,输出符合要求的区间个数
思路:求出区间的最大最小值,只要他们的差值小于k,那么这个区间就符合要求,但是由于n较大,用暴力一定超时,所以就要用别的方法了;而RMQ是可以求区间的最值的,而且预处理的复杂度只有O(nlogn),而查询只是O(1)处理,这样相对来说节约了时间,再根据右端点来二分枚举左端点(其实不用二分好像更快,估计是数据问题)。
而另一种方法不得不说,学了C++的一定要在认真的去看一下STL的那些用法,这次用multiset来做就大大的节约时间,而且又不用思考太多,只要从左到右模拟区间,就可以了。
(RMQ+二分)代码:
1 #include <cstdio> 2 #include <cstdlib> 3 #include <cmath> 4 #include <cstring> 5 #include <iostream> 6 #include <queue> 7 #include <algorithm> 8 #include <vector> 9 #include <set> 10 using namespace std; 11 #define LL __int64 12 #define INF 0x3f3f3f3f 13 const int MAXN=100005; 14 #define mod 1000000007 15 16 int a[MAXN]; 17 LL ans; 18 int dp1[MAXN][30],dp2[MAXN][30]; 19 20 void init(int n) 21 { 22 for(int i=1;i<=n;i++) 23 dp1[i][0]=dp2[i][0]=a[i]; 24 for(int j=1;(1<<j)<=n;j++) 25 { 26 for(int i=1;i+(1<<j)-1<=n;i++) 27 { 28 dp1[i][j]=max(dp1[i][j-1],dp1[i+(1<<(j-1))][j-1]); 29 dp2[i][j]=min(dp2[i][j-1],dp2[i+(1<<(j-1))][j-1]); 30 } 31 } 32 } 33 34 int RMQ(int L,int R) 35 { 36 int k=0; 37 while((1<<(k+1))<=R-L+1)k++; 38 return max(dp1[L][k],dp1[R-(1<<k)+1][k])-min(dp2[L][k],dp2[R-(1<<k)+1][k]); 39 } 40 41 int binarySearch(int L,int R,int n,int k) 42 { 43 int mid; 44 int l=L,r=R; 45 while(l<=r) 46 { 47 mid=(l+r)/2; 48 if(RMQ(mid,R)>=k) 49 { 50 l=mid+1; 51 } 52 else 53 { 54 r=mid-1; 55 } 56 } 57 if(RMQ(mid,R)>=k) 58 mid++; 59 return mid; 60 } 61 int main() 62 { 63 int T,i,j,n,k,mi,ma,l,r; 64 while(~scanf("%d",&T)) 65 { 66 while(T--) 67 { 68 scanf("%d%d",&n,&k); 69 for(i=1;i<=n;i++) 70 scanf("%d",&a[i]); 71 if(!k) 72 { 73 printf("0\n"); 74 continue; 75 } 76 if(k==1) 77 { 78 printf("%d\n",n); 79 continue; 80 } 81 init(n); 82 ans=0; 83 for(i=j=1;i<=n;i++) 84 { 85 j=binarySearch(j,i,n,k); 86 ans+=i-j+1; 87 } 88 printf("%I64d\n",ans); 89 } 90 } 91 return 0; 92 }
(STL)代码:
1 #include <cstdio> 2 #include <cstdlib> 3 #include <cmath> 4 #include <cstring> 5 #include <iostream> 6 #include <queue> 7 #include <algorithm> 8 #include <vector> 9 #include <set> 10 using namespace std; 11 #define LL __int64 12 #define INF 0x3f3f3f3f 13 const int MAXN=100005; 14 #define mod 1000000007 15 16 int a[100005]; 17 LL ans; 18 int main() 19 { 20 int T,i,j,n,k,mi,ma,l,r; 21 while(~scanf("%d",&T)) 22 { 23 while(T--) 24 { 25 scanf("%d%d",&n,&k); 26 for(i=0;i<n;i++) 27 scanf("%d",&a[i]); 28 if(!k) 29 { 30 printf("0\n"); 31 continue; 32 } 33 if(k==1) 34 { 35 printf("%d\n",n); 36 continue; 37 } 38 l=0; 39 r=1; 40 multiset<int>s; 41 s.insert(a[0]); 42 ans=n; 43 while(1) 44 { 45 if(s.size()) 46 { 47 mi=*s.begin(); 48 ma=*s.rbegin(); 49 if(abs(a[r]-mi)<k&&abs(a[r]-ma)<k) 50 { 51 ans+=s.size(); 52 s.insert(a[r]); 53 r++; 54 if(r==n) 55 break; 56 } 57 else 58 { 59 if(s.size()) 60 s.erase(s.find(a[l])); 61 l++; 62 } 63 } 64 else 65 { 66 l=r; 67 s.insert(a[r]); 68 r++; 69 if(r==n) 70 break; 71 } 72 } 73 printf("%I64d\n",ans); 74 } 75 } 76 return 0; 77 }