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
解题思路
折半搜索,先把前面一半的所有可能S存入HASH,再把后面一半的所有可能求出,如果可以在HASH中找到,并且是它的相反数(S和-S),那么答案累计
#include<iostream>
#include<cstdio>
#include<cmath>
#define ll long long
using namespace std;
const ll F=4000037;
ll n,m,a[7],b[7],ha[F][2],mid;
long long ans;
ll cf(ll x,ll y)//快速幂
{
ll ans=1;
while(y)
{
if(y&1) ans*=x;
x*=x;
y>>=1;
}
return ans;
}
ll find(ll x){//存入HASH表
ll cnt=x%F,i=0;
while(i<F&&ha[(cnt+i)%F][0]&&ha[(cnt+i)%F][0]!=x)
i++;
return ((cnt+i)%F);
}
void into(ll x){//记录数量
ha[find(x)][0]=x,++ha[find(x)][1];
}
void dfs(ll dep,ll sum){//前一半搜索
if(dep==mid){
for(ll i=1;i<=m;i++)
into(sum+a[dep]*cf(i,b[dep]));
}
else {
for(ll i=1;i<=m;i++)
dfs(dep+1,sum+a[dep]*cf(i,b[dep]));
}
}
void DFS(ll dep,ll sum){//后一半搜索
if(dep==n){
for(ll i=1;i<=m;i++){
long long t=-1*(sum+a[dep]*cf(i,b[dep]));//*-1很重要,判断当前数的相反数存不存在
if(ha[find(abs(t))][0]==abs(t))
ans+=ha[find(abs(t))][1];
}
}else
for(ll i=1;i<=m;i++)
DFS(dep+1,sum+a[dep]*cf(i,b[dep]));
}
int main(){
scanf("%lld%lld",&n,&m);
for(ll i=1;i<=n;i++)
scanf("%lld%lld",&a[i],&b[i]);
mid=n/2;
if(n==1){
if(!a[1]) printf("%lld\n",m);
else printf("0");
return 0;
}
dfs(1,0);
DFS(mid+1,0);
printf("%lld",ans);
}