[poj2785]4 Values whose Sum is 0(hash或二分)

4 Values whose Sum is 0
Time Limit: 15000MSMemory Limit: 228000K
Total Submissions: 19322Accepted: 5778
Case Time Limit: 5000MS

Description

The SUM problem can be formulated as follows: given four lists A, B, C, D of integer values, compute how many quadruplet (a, b, c, d ) ∈ A x B x C x D are such that a + b + c + d = 0 . In the following, we assume that all lists have the same size n .

Input

The first line of the input file contains the size of the lists n (this value can be as large as 4000). We then have n lines containing four integer values (with absolute value as large as 2 28 ) that belong respectively to A, B, C and D .

Output

For each input file, your program has to write the number quadruplets whose sum is zero.

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 

Hint

Sample Explanation: Indeed, the sum of the five following quadruplets is zero: (-45, -27, 42, 30), (26, 30, -10, -46), (-32, 22, 56, -46),(-32, 30, -75, 77), (-32, -54, 56, 30).

(是不是先得翻译 )题意大概是给定四个长度为n的数组,求四个数组各取一个元素和为0的取法有几种(考虑顺序)

 首先有两种做法,一种二分,一种哈希

 看一眼数据规模知道枚举每一位的O(n^4)绝对超时

 所以观察题目,发现只要求和为0,那么考虑只枚举出前两个数组的任意元素和与后两个数组任意元素和

 这样再枚举一遍前两个数组的任意元素和,检查是否有对应元素和为0即可

 接下来还要再优化

 二分写得很简单,具体代码在《挑战程序设计竞赛》第23页 不想写  

再来看哈希

把两数组的元素和得出一个键值(就是哈希值)接下来链式储存进去

什么叫链式呢?就是和邻接表差不多

把哈希映射的数组当成head数组,把原值当成边,存原值和next也就是哈希值相同的下一个值的为止 

注意这道题还得再优化,多存一个同一数值的重复次数而不是分开存,不然会MLE没错这是省空间用的

 1 #include<stdio.h>
 2 #include<stdlib.h>
 3 #include< string.h>
 4  const  int mod= 1000007;
 5 typedef  struct{
 6          int val;
 7          int num;
 8          int next;
 9 }node;
10  int data[ 4005][ 4];
11  int n,tot= 0;
12  int hash[mod+ 1];
13 node all[ 16000000];
14  int abs( int num){
15      return num> 0?num:(- 1)*num;//考虑负数!考虑负数!考虑负数!
16 }
17  int  get( int num){
18      return (abs(num))%mod;
19 }
20  int add( int num){
21      int tmp= get(num);
22      int p= 1;
23      if(hash[tmp]){
24         for(p=hash[tmp];p!= 0;p=all[p].next){
25             if(all[p].val==num){
26               all[p].num++;
27                break;
28            }
29        }
30     }
31      if((!hash[tmp])||(p== 0)){
32           all[++tot].val=num;
33           all[tot].num= 1;
34           all[tot].next=hash[tmp];
35           hash[tmp]=tot;
36     }
37      return  0;
38 }
39  int find( int num){
40      int tmp= get(num);
41      int p;
42      for(p=hash[tmp];p;p=all[p].next){
43          if(all[p].val==num) return all[p].num;
44     }
45      return  0;
46 }
47  int main(){
48     memset(hash, 0, sizeof(hash));
49     memset(all, 0, sizeof(all));
50      int n;
51     scanf( " %d ",&n);
52      for( int i= 1;i<=n;i++)scanf( " %d %d %d %d ",&data[i][ 1],&data[i][ 2],&data[i][ 3],&data[i][ 4]);
53      for( int i= 1;i<=n;i++) for( int j= 1;j<=n;j++)add(data[i][ 1]+data[j][ 2]);
54      int ans= 0;
55      for( int i= 1;i<=n;i++) for( int j= 1;j<=n;j++)ans+=find(-(data[i][ 3]+data[j][ 4]));
56     printf( " %d ",ans);
57      return  0;

58 } 

转载于:https://www.cnblogs.com/Pumbit-Legion/p/5574572.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值