链接:
https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=3593
题意:
给定4个n(1≤n≤4000)元素集合A, B, C, D,要求分别从中选取一个元素a, b, c, d,使得a+b+c+d=0。问:有多少种选法?
分析:
中途相遇法 + 散列表
首先枚举c和d,把所有-c-d记录下来放在散列表里,然后枚举a和b,查一查a+b有多少种方法写成-c-d的形式。
代码:
1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 5 const int UP_HASH = 1000000; 6 7 struct NODE { 8 int val, num, next; 9 } node[UP_HASH * 10]; 10 11 int np, head[UP_HASH], a[4][4000+5]; 12 13 inline int cor(int n){ 14 return abs(n) % (UP_HASH - 5) + 1; 15 } 16 17 int amount(int v){ 18 int h = cor(v); 19 int i = head[h]; 20 while(i){ 21 if(node[i].val == v) return node[i].num; 22 i = node[i].next; 23 } 24 return 0; 25 } 26 27 void add(int v){ 28 int h = cor(v); 29 int i = head[h]; 30 while(i){ 31 if(node[i].val == v){ 32 node[i].num++; 33 return; 34 } 35 i = node[i].next; 36 } 37 node[np].val = v; 38 node[np].num = 1; 39 node[np].next = head[h]; 40 head[h] = np++; 41 } 42 43 int main(){ 44 int T, n; 45 scanf("%d", &T); 46 while(T--){ 47 scanf("%d", &n); 48 for(int i = 0; i < n; i++){ 49 scanf("%d%d%d%d", &a[0][i], &a[1][i], &a[2][i], &a[3][i]); 50 } 51 np = 1; 52 memset(head, 0, sizeof(head)); 53 for(int t = 0; t < n; t++){ 54 for(int i = 0; i < n; i++) add(-a[2][t] - a[3][i]); 55 } 56 int ans = 0; 57 for(int t = 0; t < n; t++){ 58 for(int i = 0; i < n; i++) ans += amount(a[0][t] + a[1][i]); 59 } 60 printf("%d\n", ans); 61 if(T) printf("\n"); 62 } 63 return 0; 64 }