UVa-1152-和为0的四个值

暴力O(n4)超时。

思路1:二分。

枚举所有a+b(a属于A[],依次类推),把所有 a+b 记录下来放在一个数组sum中,对sum排序。然后枚举所有 -c-d ,在 sum 中二分查找有几个这样的值,用upper_bound() - lower_bound() 就是个数,累计到结果中。 O(n^2logn)
运行 2750ms

#include <cstdio>
#include <algorithm> 
using namespace std;
#define LL long long int
#define maxn 4005
int T,n,A[maxn],B[maxn],C[maxn],D[maxn],sum[maxn*maxn];
int main()
{
    //freopen("in.txt","r",stdin);
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        for( int i=0; i<n; ++i )
        {
            scanf("%d%d%d%d",&A[i],&B[i],&C[i],&D[i]);
        }
        int c=0;
        for( int i=0; i<n; ++i ){
            for( int j=0; j<n; ++j ){
                sum[c++]=A[i]+B[j];
            }
        }
        sort(sum,sum+c);
        LL ans=0;
        for( int i=0; i<n; ++i ){
            for( int j=0; j<n; ++j ){
                ans+=upper_bound(sum,sum+c,-C[i]-D[j])-lower_bound(sum,sum+c,-C[i]-D[j]);
            }
        }
        printf("%lld\n",ans);
        if(T) printf("\n");
    }
    //fclose(stdin);
    return 0;
}

思路2:哈希

还是和之前一样枚举 a+b ,只是这次不是放在数组 sum 中,而是hash映射到某一个值(出现次数)。枚举 -c-d 时直接通过 hash函数找到值,累计到结果。 O(n^2)
运行 490ms
哈希函数:

struct hash_mp{
	static const int N = 0x7fffff;
	int num[N],vis[N];
	void clear(){
		memset( vis,0,sizeof(vis) );
	}
	int& operator[](int k){
		int i;
		for( i=k&N; vis[i]&&num[i]!=k; i=(i+1)&N ) ;
		num[i] = k;
		return vis[i];
	}
}hash1;

hash1[]并不用很大,但是它能处理的数却很大。这是因为重载了运算符[]。对于 k ,先通过位运算中的 & 将其控制在数组上限之内,不断哈希,如果hash1(k)的值已经被占用且存的不是这个值,说明这个位置被其他占了,只能继续哈希,直到找到空位,赋值,返回访问次数。

#include <cstdio>
#include <cstring>
using namespace std;
#define LL long long int
#define maxn 4005
int T,n,A[maxn],B[maxn],C[maxn],D[maxn];

struct hash_mp{
	static const int N = 0x7fffff;
	int num[N],vis[N];
	void clear(){
		memset( vis,0,sizeof(vis) );
	}
	int& operator[](int k){
		int i;
		for( i=k&N; vis[i]&&num[i]!=k; i=(i+1)&N ) ;
		num[i] = k;
		return vis[i];
	}
}hash1;

int main()
{
	//freopen("in.txt","r",stdin);
	scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        for( int i=0; i<n; i++ )
            scanf("%d%d%d%d",&A[i],&B[i],&C[i],&D[i]);
            
		hash1.clear();
        for( int i=0; i<n; i++ ){
            for( int j=0; j<n; j++ ){
                hash1[A[i]+B[j]]++;
            }
        }
        LL ans=0;
        for( int i=0; i<n; i++ ){
            for( int j=0; j<n; j++){
               ans+= hash1[-C[i]-D[j]];
            }
        }
        printf("%lld\n",ans);
        if(T) printf("\n");
    }
    //fclose(stdin);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/CY05627/article/details/87907338