[折半搜索][哈希]POJ1186方程的解数

题目传送门

这道题明显N数据范围非常小,但是M很大,所以用折半搜索实现搜索算法的指数级优化,将复杂度优化到O(M^(N/2))。

将搜出的两半结果用哈希的方式合并(乘法原理)。

Code:

#include <cstdio>
#include <algorithm>
#define Kss 10000000
using namespace std;

int N,hf,kl[11],kr[11],pl[11],pr[11],M;
int Gl[Kss],Gr[Kss],Cl,Cr;

int ksm(int x,int y){int Res=1;while(y){if(y&1)Res*=x;x*=x;y>>=1;}return Res;}

void searchl(int x,int tot){
    if(x==hf+1){Gl[++Cl]=tot;return ;}
    for(int i=1;i<=M;i++)searchl(x+1,tot+kl[x]*ksm(i,pl[x]));
}

void searchr(int x,int tot){
    if(x==N-hf+1){Gr[++Cr]=tot;return ;}
    for(int i=1;i<=M;i++)searchr(x+1,tot+kr[x]*ksm(i,pr[x]));
}

int Ans=0;
int hs[Kss],Cts[Kss];

void hash(int x){int k=x>0?x:-x;k%=Kss;while(hs[k]!=x&&hs[k]!=-2e9)k=k%Kss+1;hs[k]=x,Cts[k]++;}
int find(int x){int k=x>0?x:-x;k%=Kss;while(hs[k]!=x&&hs[k]!=-2e9)k=k%Kss+1;return Cts[k];}

int main()
{
    scanf("%d%d",&N,&M);
    for(int i=0;i<Kss;i++)hs[i]=-2e9;
    hf=N>>1;
    for(int i=1;i<=hf;i++)scanf("%d%d",&kl[i],&pl[i]);
    for(int i=1;i<=N-hf;i++)scanf("%d%d",&kr[i],&pr[i]);
    searchl(1,0),searchr(1,0);
    for(int i=1;i<=Cr;i++)Gr[i]=-Gr[i];
    for(int i=1;i<=Cl;i++)hash(Gl[i]);
    for(int i=1;i<=Cr;i++)Ans+=find(Gr[i]);
    printf("%d",Ans);
    return 0;
}

 

posted @ 2018-06-11 18:15  Cptraser  阅读(272)  评论(0编辑  收藏  举报