Week4 作业B 四个数列 二分

题意:

有四个数列A,B,C,D,每个数列都有n个数字(1<=n<=4000,数字不超过2^28),从每个数列中各取出一个数,计算有多少种方案使得四个数的和为0。当一个数列中有多个相同的数时,把它们当做不同的数对待。

题目分析:

如果对A,B,C,D中的每个数枚举一遍,共有n^4中情况,n<=4000显然超时。

减少枚举次数,先枚举A、B,再枚举C、D,两重循环,O(n^2),可以接受。

枚举A、B中的n*n种情况,A[i]+B[j]放在一个数组sum1中。枚举C、D中的n*n种情况,C[i]+D[j]放在一个数组sum2中。对sum2中的任何一个数x,sum1中若有y个x的相反数,则会产生y种取数方法。

在计算sum1中有多少个x的相反数时,若直接遍历,复杂度是O(n),总的复杂度变为O(n^3),也是超时的。采用二分的方法,可以把这一过程降到O(logn)。对sum1中元素排序,二分找到sum1中第一个-x的位置first和最后一个-x的位置last,last-first+1即为sum1中-x的个数。

代码:

#include
#include
#include
using namespace std;
int n;//数列中中的个数
const int maxn=4e3+5;
int a[maxn],b[maxn],c[maxn],d[maxn]; 
int sum1[maxn*maxn];
int sum2[maxn*maxn];
int findFirst(int x){
	int l=0,r=n*n-1,ans=-1;
	while(l<=r){
		int mid=(l+r)>>1;
		if(sum1[mid]==x){
			ans=mid;
			r=mid-1;
		}else if(sum1[mid]>1;
		if(sum1[mid]==x){
			ans=mid;
			l=mid+1;
		}else if(sum1[mid]

 

你可能感兴趣的:(#,二分)