题目链接:N - 方程的解
给定一个四元二次方程:
$Ax1^2+Bx2^2+Cx3^2+Dx4^2=0$
试求$−1000≤x1,x2,x3,x4≤1000$非零整数解的个数。
$−10000≤A,B,C,D≤10000$
输出解的个数。
解法:
首先这道题直接用网上HDU1496的板子过不去,原因是1e10的数组开不了那么大的。所以这里只能换思路。新思路如下(很典型的折半枚举,也就是meet-in-middle):
- 把X1,X2的答案存下来(存在一个2000*2000的数组里面),然后排序
- 二分查找这个数组里面有多个数x了
- $AX_1^2+BX_2^2=-(CX_3^2+DX_4^2)$
- 左边式子的答案我们已经存下来了,接下来算右边的
- 右边答案算出来过后,我们直接在左边数组里面二分有多少个一样的数值,答案加上这个数值就ok了
当然这里用数组会稍显笨拙,可以用map,卡时间可以过。
注意s[a*i*i + b*j*j]++
会爆int,因此需要将a改为long long
代码如下:
1 #include<cstdio> 2 #include<map> 3 #include<algorithm> 4 using namespace std; 5 typedef long long ll; 6 map<ll, ll>s; 7 8 int main() { 9 ll a, b, c, d; 10 while (scanf("%lld %lld %lld %lld", &a, &b, &c, &d) != EOF) { 11 if (a * b > 0 && b * c > 0 && c * d > 0) { 12 printf("0 "); 13 return 0; 14 } 15 for (ll i = 1; i <= 1000; i++) { 16 for (ll j = 1; j <= 1000; j++) { 17 //if (i == 0 || j == 0)continue; 18 s[a*i*i + b*j*j]++; 19 } 20 } 21 ll sum = 0; 22 for (ll i = 1; i <= 1000; i++) { 23 for (ll j = 1; j <= 1000; j++) { 24 //if (i == 0 || j == 0)continue; 25 ll t = c*i*i + d*j*j; 26 sum += s[0 - t]; 27 } 28 } 29 printf("%lld ", 16*sum); 30 } 31 return 0; 32 }
上面说了卡常数不是很严的做法,如果卡常数很严的话,比如x的范围变到4000,map就会T掉,这里直接采用hash的方法
关键词:数字hash
例题:Uva1152:4 Values whose Sum is 0
1 //hash数字编码 2 #include<cstdio> 3 #include<vector> 4 #include<algorithm> 5 #include<cstring> 6 #include<map> 7 using namespace std; 8 typedef long long ll; 9 map<ll, ll>s; 10 int a[4005], b[4005], c[4005], d[4005]; 11 int n, T, cnt; 12 13 //w[i]表示第i个结点存储的数(也就是a+b),st[i]表示第i个结点有多少种表示方法 14 const int hashsize = 1000003; 15 int hd[hashsize], nxt[16000005], w[16000005], st[16000005]; 16 void in(int x) { 17 int h = (x % hashsize + hashsize) % hashsize, u = hd[h]; 18 while (u) { 19 if (w[u] == x) { 20 st[u]++; 21 return; 22 } 23 u = nxt[u]; 24 } 25 nxt[++cnt] = hd[h]; 26 hd[h] = cnt; 27 w[cnt] = x; 28 st[cnt] = 1; 29 } 30 31 int srch(int x) { 32 int h = (x % hashsize + hashsize) % hashsize;//查询的数是负数,所以要这么算; 33 int u = hd[h]; 34 while (u) { 35 if (w[u] == x) return st[u]; 36 u = nxt[u]; 37 } 38 return 0; 39 } 40 41 int main() { 42 scanf("%d", &T); 43 while (T--) { 44 cnt = 0; memset(hd, 0, sizeof(hd)); 45 scanf("%d", &n); 46 int A, B, C, D; 47 for (int i = 0; i < n; i++) { 48 scanf("%d%d%d%d", &a[i], &b[i], &c[i], &d[i]); 49 } 50 for (ll i = 0; i < n; i++) { 51 for (ll j = 0; j < n; j++) { 52 in(a[i] + b[j]); 53 } 54 } 55 ll sum = 0; 56 for (int i = 0; i < n; i++) { 57 for (int j = 0; j < n; j++){ 58 sum += srch(-c[i] - d[j]); 59 } 60 } 61 printf("%lld ", sum); 62 if (T) printf(" "); 63 } 64 return 0; 65 }