HDU - 5178 思维多种解答(大佬们如何巧妙的解题)
题意:输入数组a和k,求有多少对a,b,(a<b) 使得|x[b]−x[a]|≤k?
思路:1、这道题最重要的就是要解决超时这个问题,否则按暴力肯定是超时的。
2、解决超时,这里有种方法。
先将这个数组从小到大排序,然后i从0开始,tmp从0开始判断,如果值小于等于k的话,tmp++,直到>k停止,
ans加上该值。下一次,i+1,之前的i和k可以,那么和i+1更可以,所有k继续向后跑,如此复杂度大大减少。
具体看代码
普普通通版本:暴力解答(超时严重)
1 for(int i=0;i<n;i++){ 2 for(j=0;j<i;j++){ 3 if(abs(a[i]-a[j])<=k) 4 ans++; 5 } 6 }
各种大佬版本:属于大佬们的show time
one.尺取法----202ms
1 #include <algorithm> 2 #include<iostream> 3 using namespace std; 4 int a[100001]; 5 int main() 6 { 7 int n, k, t; 8 scanf("%d",&t); 9 while(t--) 10 { 11 scanf("%d%d",&n,&k); 12 long long ans = 0; 13 for(int i=0; i<n; ++i) 14 scanf("%d",&a[i]); 15 sort(a,a+n); 16 int l=0,r=0; 17 for(int l=0,r=0;l<n;l++) //尺取法 18 { 19 while(r+1<n&&a[r+1]-a[l]<=k) 20 ++r; 21 ans+=r-l; //5-1,5-2,5-3 对l边界做循环,对每个l找出有几对 22 } 23 printf("%lld\n",ans); 24 } 25 return 0; 26 }
two.二分upper_bound法-----234ms
1 # include <stdio.h> 2 # include <algorithm> 3 using namespace std; 4 int a[100001]; 5 int main() 6 { 7 int n, k, t; 8 scanf("%d",&t); 9 while(t--) 10 { 11 scanf("%d%d",&n,&k); 12 long long ans = 0; 13 for(int i=0; i<n; ++i) 14 scanf("%d",&a[i]); 15 sort(a, a+n); 16 for(int i=0; i<n-1; ++i) 17 { 18 int pos = upper_bound(a+i,a+n, a[i]+k)-a; 19 ans += pos - i - 1; 20 } 21 printf("%lld\n",ans); 22 } 23 return 0; 24 }
three.聪明法---202ms
1 #include<iostream> 2 #include<algorithm> 3 using namespace std; 4 #define N 100006 5 #define ll long long 6 int n,k; 7 int a[N]; 8 int main() 9 { 10 int t; 11 scanf("%d",&t); 12 while(t--) 13 { 14 scanf("%d%d",&n,&k); 15 for(int i=0;i<n;i++) 16 scanf("%d",&a[i]); 17 sort(a,a+n); 18 ll ans=0; 19 int tmp=0; 20 for(int i=0;i<n;i++) 21 { 22 while(abs(a[i]-a[tmp])<=k && tmp<n)//循环 23 tmp++; 24 ans+=tmp-i-1; 25 } 26 printf("%I64d\n",ans); 27 } 28 return 0; 29 }
four.二分法
1 #include<cstdio> 2 #include<algorithm> 3 //需要注意的是数据量大,用long long 类型 4 typedef long long ll; 5 int n; 6 ll k; 7 ll a[100001]; 8 using namespace std; 9 void solve(){ 10 ll ans = 0; 11 for(int i = 0; i < n; i++){//先遍历每个元素,尝试找到第一个满足条件的元素 12 ll l, r, mid; 13 l = i; 14 r = n - 1; 15 while(r >= l){ 16 mid = (l + r)/2; 17 if(a[mid] - a[i] > k){ 18 r = mid - 1;// 19 } 20 else{ 21 l = mid + 1; 22 } 23 } 24 ans += r - i; 25 } 26 printf("%I64d\n", ans); 27 } 28 29 int main(){ 30 int t; 31 scanf("%d", &t); 32 while(t--){ 33 scanf("%I64d%I64d", &n, &k); 34 for(int i = 0; i < n; i++){ 35 scanf("%I64d", &a[i]); 36 } 37 sort(a, a + n); 38 solve(); 39 } 40 }
心得:人生好苦,希望锻炼出健康的体魄和聪明的头脑!!!