SSL-ZYC 1127 方程的解数

题目大意:
这里写图片描述


思路:
肯定DFS!
一开始想枚举每个x,但是看到数据范围O(n^6)。。。
所以就想到了下面这种方法:

利用等式的性质,将后n/2个数移到等号右边,就得到了:
**k1x1^p1+k2x2^p2+k3x36^p3=-(k4x4^p4+k5x5^p5+k6x6^p6)**
这样只需分别枚举两边,利用哈希表来判断是否相等即可。

时间复杂度:O(n^3)


代码:

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;

const int emm=48651279;  //初始化用的随机数,如果该数设的很大,则与答案“撞衫”的可能性就小。
const int k=4000037;  //很大的数,在哈希函数中使用
int num[k+10],ha[k+10],a[11],b[11];
int n,m;
long long sum;

int h(int x)  //哈希函数
{
    return x%k;
}

int ksm(int x,int y)  //快速幂
{
    int ans=1;  //记录答案
    while(y>0)
    {
        if(y&1) ans*=x;
        x*=x;
        y/=2;
    }
    return ans;
}


int locate(int x)  //查找
{
    int t=h(abs(x));  //使用哈希函数
    int i=0;
    while (i<k&&ha[(t+i)%k]!=x&&ha[(t+i)%k]!=emm) i++;  //直到找到一个空位或该数为止
    return (t+i)%k;
}

void insert(int x)  //插入数
{
    int y=locate(x);
    if (ha[y]==emm) ha[y]=x;
    num[y]++;  //记录该数有几个
}

bool pos(int x)  //查找一个数
{
    int y=locate(x);
    if (ha[y]!=emm) return true;
     else return false;
}

void dfs1(int x,int K)  //搜索前n/2个数
{
    if (x==n/2+1)  //如果已经搜完了
    {
        insert(K);  //插入这些数的和
        return;  //返回
    }
    for (int i=1;i<=m;i++)  //枚举x
    {
        int s=ksm(i,b[x]);
        s*=a[x];
        dfs1(x+1,K+s);  //搜索
    }
}

void dfs2(int x,int K)  //搜索后n/2个数 
{
    if (x==n+1)  //如果已经搜完了
    {
        if (pos(-K)==true) sum+=num[locate(-K)];  //查找是否在哈希表中
        return;  //返回
    }
    for (int i=1;i<=m;i++)  //枚举x 
    {
        int s=ksm(i,b[x]);
        s*=a[x];         
        dfs2(x+1,K+s);  //搜索
    }
}

int main()
{
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;i++)
     scanf("%d%d",&a[i],&b[i]);  
    for (int i=1;i<=k+9;i++)
     ha[i]=emm;
    if (n==1)  //特判
    {
        if (a[1]==0) printf("%d\n",m);
        else printf("0");
        return 0;
    }
    dfs1(1,0);
    dfs2(n/2+1,0);  //搜索
    printf("%lld\n",sum);
    return 0;
}
posted @ 2018-03-09 18:51  全OI最菜  阅读(116)  评论(0编辑  收藏  举报