[折半搜索][哈希]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; }