方程的解数

题目

Description

这里写图片描述

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


解题思路

可以选择看一下学长的分析:初看此题,题目要求出给定的方程解的个数,这个方程在最坏的情况下可以有6个未知数,而且次数由输入决定。这样就不能利用数学方法直接求出解的个数,而且注意到解的范围最多150个数,因此恐怕只能使用枚举法了。最简单的思路是穷举所有未知数的取值,这样时间复杂度是 O(M^6) ,无法承受。因此我们需要寻找更好的方法,自然想到能否缩小枚举的范围呢?但是发现这样也有很大的困难。我们再次注意到M 的范围,若想不超时,似乎算法的复杂度上限应该是 O(M^3) 左右,这是因为 150^3 < 10000000 。这就启示我们能否仅仅通过枚举3个未知数的值来找到答案呢?如果这样,前一半式子的值 S 可以确定,这时只要枚举后3 个数的值,检查他们的和是否等于 -S 即可。这样只相当于在 O(M^3) 前面加了一个系数,当然还需要预先算出 1 到 150 的各个幂次的值。想到了这里,问题就是如何迅速的找到某个 S 是否曾经出现过,以及出现过了多少次,于是又变成了”某个元素是否在给定集合中”这个问题。所以,我们还是使用哈希表解决这个问题。至于哈希函数不是问题,还是把 S 的值作为关键字使用除余法即可。然而有一点需要注意,这个例子我们不仅需要纪录某个 S 是否出现,出现的次数也很重要,所以可以用一个2维数组,仅仅是加了一个存储出现次数的域而已。

对于该题,可以通过快速幂,哈希表和一些优化来提速。总体来说就是,先(dfs)枚举前半部分,然后再(dfs)后半部分,如果后面的答案是前面所求的答案的相反数,证明这也是一个方案。


代码

#include
using namespace std; 
const int maxx=4000037; 
int n,m,ans,num[maxx],middle,k[7],p[7],hs[maxx]; 
long long all;
int ksm(int x,int y)//快速幂
{
    int ans=1;
    while(y)
    {
        if(y&1) ans*=x;
        x*=x;
        y>>=1;
    }
    return ans;
}
int abs(int x)//为后面的定义用
{ if (x>=0) return x;else return -x;}
int hash(int x)//hash函数
{ x=abs(x); return x%maxx;}

int locate(int x)//定位
{
    int i=hash(x); 
    while (hs[i]&&hs[i]!=x)
     i=(i+1)%4000037;
    return i;
}

void inn(int x)//增加进哈希表里
{ hs[locate(x)]=x; num[locate(x)]++; return;} //num[]数量也要增加

bool find(int x)//是否查找到
{ if (hs[locate(x)]==x) return true;else return false;}

void dfs(int x,int y)//前半部分
{
    if (x==middle)//x表示深度,y表示当前累加的“答案”
    {
      for (int i=1;i<=m;i++)
                inn(y+k[x]*ksm(i,p[x])); 
      return;
    }else
    for (int i=1;i<=m;i++)
       dfs(x+1,y+k[x]*ksm(i,p[x])); 
}

void dfss(int x,int y)//后半部分
{
    if (x==n)
    { 
        for (int i=1;i<=m;i++)
            {
                ans=-1*(y+k[x]*ksm(i,p[x]));//注意“-1”,相当与-ans
                if(find(ans)) all+=num[locate(ans)];
            }
        return; 
    }else
    for (int i=1;i<=m;i++)
        dfss(x+1,y+k[x]*ksm(i,p[x])); 
}

int main()
{
    scanf("%d",&n); 
    scanf("%d",&m); 
    for (int i=1;i<=n;i++)
     scanf("%d%d",&k[i],&p[i]); 
    middle=n>>1;//除以2
    if(n==1)
     if(k[1]==0) //特殊情况
      {printf("%d",m);return 0;}
    else
     {putchar(48);return 0;}
    dfs(1,0); 
    dfss(middle+1,0); 
    printf("%lld",all); 
}

你可能感兴趣的:(哈希(hash),深度优先搜索(dfs))