#include <stdio.h>
#include <string.h>
// struct hashInfo {
// int val;
// char used;
// int hval;
// int solutionNum;
// };
// typedef struct hashInfo hashInfo;
// const int BIG_PRIME = 10061;
const int MAX_ADD = 2*50*50*50*50;
//hashInfo hashArray[10062];
short bighashArray[MAX_ADD*2+1];
void fillInHashArray2(int val) {
bighashArray[val + MAX_ADD]++;
}
int getA1A2SolutionNum2(int val) {
if (val > MAX_ADD || val < -MAX_ADD) {
return 0;
}
return bighashArray[val + MAX_ADD];
}
// void fillInHashArray(int val) {
// int hval = (val + MAX_ADD)%BIG_PRIME;
// int fillPos = hval;
// while(1) {
// if (!hashArray[fillPos].used) {
// hashArray[fillPos].used = 1;
// hashArray[fillPos].val = val;
// hashArray[fillPos].hval = hval;
// hashArray[fillPos].solutionNum = 1;
// break;
// } else {
// if (hashArray[fillPos].hval = hval) {
// if (hashArray[fillPos].val == val) {
// hashArray[fillPos].solutionNum++;
// break;
// }
// }
// fillPos++;
// if (fillPos == BIG_PRIME) {
// fillPos = 0;
// }
// }
// }
// }
// int getA1A2SolutionNum(int val) {
// if (val > MAX_ADD || val < -MAX_ADD) {
// return 0;
// }
// int hval = (val + MAX_ADD)%BIG_PRIME;
// int Pos = hval;
// char byPass1Round = 0;
// while(1) {
// if (Pos == hval && byPass1Round) {
// return 0;
// }
// if (!hashArray[Pos].used) {
// return 0;
// } else {
// if (hashArray[Pos].hval = hval) {
// if (hashArray[Pos].val == val) {
// return hashArray[Pos].solutionNum;
// }
// }
// Pos++;
// if (Pos == BIG_PRIME) {
// byPass1Round = 1;
// Pos = 0;
// }
// }
// }
// }
int getSolutionNum(int a1, int a2, int a3, int a4, int a5) {
int solutionNum = 0;
memset(bighashArray, 0, sizeof(bighashArray));
for (int i = 1; i <= 50; i++) {
for (int j = 1; j <= 50; j++) {
int A1 = a1*i*i*i;
int A2 = a2*j*j*j;
int val1 = A1 + A2;
int val2 = A2 - A1;
int val3 = -val2;
int val4 = -val1;
fillInHashArray2(val1);
fillInHashArray2(val2);
fillInHashArray2(val3);
fillInHashArray2(val4);
}
}
for (int i = 1; i <= 50; i++) {
for (int j = 1; j <= 50; j++) {
for (int k = 1; k <= 50; k++) {
int A3 = a3*i*i*i;
int A4 = a4*j*j*j;
int A5 = a5*k*k*k;
int TMP1 = A3 + A4;
int TMP2 = A4 + A5;
int TMP3 = A3 + A5;
int val1 = A3 + TMP2;
int val2 = -val1;
int val3 = -A3 + TMP2;
int val4 = -val3;
int val5 = -A4 + TMP3;
int val6 = -val5;
int val7 = -A5 + TMP1;
int val8 = -val7;
solutionNum += getA1A2SolutionNum2(val1);
solutionNum += getA1A2SolutionNum2(val2);
solutionNum += getA1A2SolutionNum2(val3);
solutionNum += getA1A2SolutionNum2(val4);
solutionNum += getA1A2SolutionNum2(val5);
solutionNum += getA1A2SolutionNum2(val6);
solutionNum += getA1A2SolutionNum2(val7);
solutionNum += getA1A2SolutionNum2(val8);
}
}
}
printf("%d\n", solutionNum);
return solutionNum;
}
int main() {
int a1;
int a2;
int a3;
int a4;
int a5;
while(scanf("%d %d %d %d %d", &a1, &a2, &a3, &a4, &a5) > 0) {
getSolutionNum(a1, a2, a3, a4, a5);
}
}
G++ 49324K 516MS.
这道题一开始想歪了,想着用DP搞,后来看了一下数据范围,直接放弃了。
然后从朴素的思路入手,如果想穷举并举最前2/3 个三次方的值分布, 然后再遍历后3/2个三次方的取值并查看是否有相反的取值即可(选择2/3 是因为这样可以最大限度的
减少运算次数,这样就是 O(n3 + n2), 而如果是 1/4的话 就是 O(n1 + n4)), 那么问题就成怎么记录前面2/3个三次方多项式的值的分布了,
很自然就就是hash了(还有人用排序数组,然后二分查找,也可以,时间换空间)
接下来就是hash数组该开多大, 如果选择记录前2个3次方的话,总共有100*100种可能的分布(2个变量,每个有100种取值,还可能更小,这里面还可能会有重叠的值, 一开始想岔了,还以为有值范围那么大的可能,忘了是离散分布的,妈的,基础知识要呀),这样,开个10000就够了,不过因为这次的hash有些特殊需求,还要求能够检测值是否存在,那么最坏的情况下,为了确定不存在,因为我用的是开放寻址,可能要遍历整个hash数组,结果TLE了。那么,空间换时间吧,直接开了个 2* 50*50*50*50大小的hash数组, 把所有的值直接包进去,直接避免了碰撞,如果由相同的值多次进入,就++,这样最后这个数组里就是存储对于前2个3次方多项式等于某个值K的solution的num(这就是这类题的唯一特别之处,hash存储的不光是是否存在,还有更多信息).
接下就直接遍历后3个多项式的可能取值然后从前面得到的数组里查看相反值有多少种解即可,不断累加,最后输出.
要看看一般的hashmp 开放寻址对于不存在的值有没有好的不需要遍历整个数组的检测方法.