天天看點

poj 1186 方程的解數 (hash+雙向dfs)

Description

已知一個n元高次方程:

poj 1186 方程的解數 (hash+雙向dfs)

其中:x1, x2,...,xn是未知數,k1,k2,...,kn是系數,p1,p2,...pn是指數。且方程中的所有數均為整數。

假設未知數1 <= xi <= M, i=1,,,n,求這個方程的整數解的個數。

1 <= n <= 6;1 <= M <= 150。

poj 1186 方程的解數 (hash+雙向dfs)

方程的整數解的個數小于2 31。

★本題中,指數Pi(i=1,2,...,n)均為正整數。

Input

第1行包含一個整數n。第2行包含一個整數M。第3行到第n+2行,每行包含兩個整數,分别表示ki和pi。兩個整數之間用一個空格隔開。第3行的資料對應i=1,第n+2行的資料對應i=n。

Output

僅一行,包含一個整數,表示方程的整數解的個數。

Sample Input

3
150
1  2
-1  2
1  2      

Sample Output

178      

Source

Noi 01

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;
typedef long long ll;
const int maxn=5000001;
struct hash
{
    int val;
    int count;
}hashset[maxn];
int ki[10],pi[10];
int n,m,sum,mid;
int gethash(int k)
{
    int x=((k%maxn)+maxn)%maxn;
    while(hashset[x].count>0&&hashset[x].val!=k)
    {
        x=(x+1)%maxn;
    }
    return x;
}
int quickmod(int a,int b)
{
    int ans=1;
    while(b)
    {
        if(b&1)
            ans=ans*a;
        b>>=1;
        a=a*a;
    }
    return ans;
}
void dfs1(int i, int k)
{
    if(i==mid)
    {
        int pos=gethash(k);
        hashset[pos].val=k;
        hashset[pos].count++;
        return ;
    }
    for(int u=1;u<=m;u++)
        dfs1(i+1,k+ki[i+1]*quickmod(u,pi[i+1]));
}
void dfs2(int i,int k)
{
    if(i==(mid+1))
    {
        int pos=gethash(k);
        sum+=hashset[pos].count;
        return ;
    }
    for(int u=1;u<=m;u++)
        dfs2(i-1,k-ki[i-1]*quickmod(u,pi[i-1]));
}
int main()
{
    int i;
    while(~scanf("%d%d",&n,&m))
    {
        mid=n/2;
        sum=0;
        for(i=1;i<=n;i++)
            scanf("%d%d",&ki[i],&pi[i]);
        dfs1(0,0);
        dfs2(n+1,0);
        printf("%d\n",sum);
    }
    return 0;
}