随笔 - 97, 文章 - 22, 评论 - 81, 引用 - 0
数据加载中……

PKU 1186 方程的解数

题目链接: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(
00);

        
int ans = 0;
        
if(n <= split) {
            ans 
= Query(0);
        }
else {
            dfs1(split, 
0, ans);
        }

        printf(
"%d\n", ans);
    }

    
return 0;
}

posted on 2011-04-09 23:55 英雄哪里出来 阅读(1162) 评论(0)  编辑 收藏 引用 所属分类: 数学


只有注册用户登录后才能发表评论。
【推荐】超50万行VC++源码: 大型组态工控、电力仿真CAD与GIS源码库
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理