题目大意:
思路:
肯定DFS!
一开始想枚举每个x,但是看到数据范围O(n^6)。。。
所以就想到了下面这种方法:
利用等式的性质,将后n/2个数移到等号右边,就得到了:
这样只需分别枚举两边,利用哈希表来判断是否相等即可。
时间复杂度: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;
}