B-四个数列

Sample Input
6
-45 22 42 -16
-41 -27 56 30
-36 53 -37 77
-36 30 -75 -46
26 -38 -10 62
-32 -54 -6 45
Sample Output
5
解:事实证明这道题暴力肯定会超时。根据老师在课堂上讲,可以先把A,B两个数组的数自由组合加起来,C,D两个数组的数自由组合加起来,然后利用sort函数把CD排序,对一个有序数组,已知一个元素值,通过二分法查找与之对应的相反数。那么就可以把时间复杂度降为O(nlogn)
#include<algorithm>
using namespace std;
int A[4001],B[4001],C[4001],D[4001];
int n,tag,sum;
int AB[16000001],CD[16000001];
void half(){//折半查找
int mid,tag1,tag2;
for(int i=0;i<tag;i++){
tag1=0;tag2=tag;
while(tag2>tag1){
mid=(tag1+tag2)>> 1;
if(AB[i] + CD[mid] >= 0)//说明CD[mid]比较大
tag2=mid;
else tag1=mid+1;//CD[mid]比较小
}
while(AB[i]+CD[tag1]==0 && tag1<tag){
sum++;
tag1++;
}
}
cout<<sum<<endl;
}
int main(){
tag=0,sum=0;
cin>>n;
for(int i=0;i<n;i++)
cin>>A[i]>>B[i]>>C[i]>>D[i];
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
AB[tag]=A[i]+B[j];
CD[tag]=C[i]+D[j];
tag++;
}
}
sort(CD,CD+tag,less<int>());
half();
return 0;
}

Sample Input
4
1 3 2 4
3
1 10 2
Sample Output
1
8
我再提供一些测试数据吧
Input
5
2 3 4 15 99
6
1 5 13 24 32 45
7
1 2 3 4 5 6 7
Output
12
19
2
解:
同样的,如果这道题采用暴力解法,就是枚举i,j。将ans的结果直接算出来,然后直接得到它的中位数。时间复杂度O(n^2).接下来我们考虑降低时间复杂度的方法:
首先用sort函数将cat数组元素升序排序,也即是去绝对值。说到绝对值,补充概念:abs,fabs(代码说明)
#include<iostream>
#include<math.h>
using namespace std;
int main(){
int a=5,b=-6,xa,xb;
xa=abs(a);
xb=abs(b);
cout<<xa<<" "<<xb<<endl;
return 0;
}
输出结果:
5 6
对于fabs,其适用于浮点数取绝对值,比如fabs(-3.67)=3.67
跳过这段小插曲,我们继续讨论本题。排序后,可以保证cat[j]始终是比cat[i]要大,因为n>=j>i.接着我们就要用二分法去找新数组中位数,怎么找?
首先我们来看看传统的二分法搜索:
int binarySearch(int* array, int target) {
int left = 0;
int right = nums.length - 1;
while(left <= right) {
int mid = (right + left) / 2;
if(array[mid] == target)
return mid;
else if (array[mid] < target)
left = mid + 1;
else if (array[mid] > target)
right = mid - 1;
}
return -1;
}
在一个数组里搜索一个数,如果找到了,就返回其索引,如果找不到,就返回-1.那么上诉的条件是已知一个数组,而且知道我要查找的这个数的值,求其索引。
反观本题,是有一个原始数组,另一个数组可求,知道是中位数,就是我们所说的索引,去找那个数的值,那么我们不妨把right和left由开始的索引(位置)换成值,去找中位数。代码如下(结尾有彩蛋):
#include<iostream>
#include<algorithm>
#include<stdio.h>
using namespace std;
int n,mid,maxele,midlocate,tag,tag1,ans,maxlocate;
int cat[100001];
//int ans[10000000001];//cat[j]-cat[i],知道了这个数的位置,去找这个数
int binarySearch(){
//int left=0,right=n*(n-1)/2 - 1;
tag1=maxele;ans=0;
while(ans < tag1){
mid=(ans+tag1)/2;tag=0;
for(int i=0;i<n;i++)
tag+=n-(lower_bound(cat,cat+n,cat[i]+mid)-cat);
if(tag > (maxlocate-midlocate))
ans=mid+1;
else if (tag <= (maxlocate-midlocate))
tag1 = mid;
}
ans--;
return ans;
}
int main(){
while(scanf("%d",&n)!= EOF){
for(int i=0;i<n;i++)
scanf("%d",&cat[i]);
//cin>>cat[i];
sort(cat,cat+n,less<int>());
maxele=cat[n-1]-cat[0];//先找到最大值,它肯定在最后一个位置
//n*(n-1)/2-1处
maxlocate=n*(n-1)/2-1;
midlocate=(n*(n-1)/2 +1)/2-1;
cout<<binarySearch()<<endl;
}
return 0;
}
这道题的提交过程可谓是一波三折:
它居然不支持less<int>,(╬◣д◢)
解决办法:换为G++

emmm,我把头文件改为#include<stdio.h>就可以了
但是,它又超时了,原来是cin的问题,用scanf就没事了,为什么呢,难道cin的时候还要去判断一下我输入的是个什么类型,scanf在输入时我就直接告诉它了.(我的粗鄙理解)
放1张可爱猫咪老师图片,美化一下这篇单调的博客:

本文探讨了四数求和问题的高效算法,通过预处理和二分查找将时间复杂度降至O(nlogn)。同时,详细解析了如何利用排序和二分查找快速确定中位数,避免了暴力解法的高时间成本。

5758

被折叠的 条评论
为什么被折叠?



