|
题目链接:http://poj.org/problem?id=1186
/**//* 题意: 已知一个n元高次方程: 其中:x1, x2,,xn是未知数,k1,k2,,kn是系数,p1,p2,pn是指数。 且方程中的所有数均为整数。 假设未知数1 <= xi <= M, i=1,,,n,求这个方程的整数解的个数。 1 <= n <= 6;1 <= M <= 150。 方程的整数解的个数小于2^31。 ★本题中,指数Pi(i=1,2,,n)均为正整数。
题解: DFS + HASH
思路: 一看到题目以为是解方程的,仔细一看,其实不然,题目有一个条件就是 未知数的数目n很小,只有6,而且未知数也是有上限(1 <= M <= 150),所以 当最大情况的时候可以枚举3个未知数的值,一共150^3,然后插入到hash表中, 再枚举另外三个组成的所有情况,每次得到一个和为S时,只要查询hash表中-S 的数的数量,加到最后的答案即可。 这样就把本来150^6的复杂度开了个根号。枚举数的时候因为n是不确定的 ,所以我采用dfs来枚举,这样写起来会方便许多。 */
#include <iostream>
using namespace std;
#define maxn 4642307 #define ll __int64 int split;
int nowPos[maxn], Case; int hash[maxn]; int key[maxn];
int n, M;
int EXP(int a, int b) { if(b == 0) return 1; int tmp = EXP(a*a, b/2); if(b & 1) tmp *= a; return tmp; }
struct point { int k, p; }pt[6];
void Insert(int val) { int s = val % maxn; if(s < 0) s += maxn;
while(1) { if(nowPos[s] != Case) { nowPos[s] = Case; hash[s] = 1; key[s] = val; return ; }else { if(key[s] == val) { hash[s] ++; return ; } s ++; if(s == maxn) s = 0; } } }
int Query(int val) { int s = val % maxn; if(s < 0) s += maxn; while(1) { if(nowPos[s] != Case) { return 0; }else { if(key[s] == val) { return hash[s]; } s ++; if(s == maxn) s = 0; } } }
void dfs0(int depth, int sum) { if(depth == split || depth == n) { Insert(sum); return ; } int i; for(i = 1; i <= M; i++) { dfs0(depth+1, sum + pt[depth].k * EXP(i, pt[depth].p) ); } }
void dfs1(int depth, int sum, int& ans) { if(depth == n) { ans += Query(- sum); return ; } int i; for(i = 1; i <= M; i++) { dfs1(depth+1, sum + pt[depth].k * EXP(i, pt[depth].p), ans ); } }
int main() { int i; while(scanf("%d %d", &n, &M) != EOF) {
if(n <= 4) { split = 2; }else split = 3;
Case ++; for(i = 0; i < n; i++) { scanf("%d %d", &pt[i].k, &pt[i].p); } dfs0(0, 0);
int ans = 0; if(n <= split) { ans = Query(0); }else { dfs1(split, 0, ans); } printf("%d\n", ans); } return 0; }
|