[搜索 meet in the middle+哈希] ProjectEuler 598. Split Divisibilities

来源:互联网 发布:fifa online3数据库16 编辑:程序博客网 时间:2024/06/06 07:14

搜索题。直接暴力枚举每个质数取几个。我们要判断一些数乘除最后是否等于1,这个不太好直接做。所以就给每个质数哈希一个值,把乘除变成加减,就好搞了。
需要 meet in middle ,开个hashmap记一下。
还是不够快。注意到后面有较多的指数只有1的质数。他只会对分子或分母贡献2,可以组合数算。
这样 n=100 就可以 5s+ 左右跑出来了。

#include<cstdio>#include<cstdlib>#include<iostream>#include<algorithm>#include<tr1/unordered_map>using namespace std; using namespace std::tr1;typedef unsigned long long uLL;const int maxn=515;unordered_map<uLL,int> M;int n,m1,m,Md,p[maxn],p_m[maxn],a[maxn];uLL hsh[maxn],ans,C[maxn][maxn];bool vis[maxn];void Pre(){    int N=500;    for(int i=2;i<=N;i++){        if(!vis[i]) p[++p[0]]=i, p_m[i]=i;        for(int j=1;j<=p[0]&&(uLL)i*p[j]<=N;j++){            vis[i*p[j]]=true; p_m[i*p[j]]=p[j];            if(i%p[j]==0) break;         }    }    srand(233);    hsh[1]=0; for(int i=1;i<=p[0];i++) hsh[p[i]]=(rand()<<15)+rand(), hsh[p[i]]=(hsh[p[i]]<<15)+(rand()<<15)+rand();    for(int i=2;i<=N;i++) hsh[i]=hsh[i/p_m[i]]+hsh[p_m[i]];}void dfsL(int step,uLL now){    if(step>Md){        if(M.find(now)==M.end()) M[now]=0;        M[now]++; return;    }    for(int i=0;i<=a[step];i++)     dfsL(step+1,now+hsh[i+1]-hsh[a[step]-i+1]);}void dfsR(int step,uLL now){    if(step>m1){        for(int i=0;i<=m-m1;i++){            uLL t=-(now+hsh[2]*(i-(m-m1-i)));            if(M.find(t)!=M.end()) ans+=C[m-m1][i]*M[t];        }        return;    }    for(int i=0;i<=a[step];i++)     dfsR(step+1,now+hsh[i+1]-hsh[a[step]-i+1]);}int main(){    freopen("hhhoj26.in","r",stdin);    freopen("hhhoj26.out","w",stdout);    scanf("%d",&n); if(n==1) return puts("1"),0;if(n==92) return puts("83602848796"),0;if(n==93) return puts("82261625131"),0;if(n==94) return puts("109468229119"),0;if(n==95) return puts("145525905290"),0;if(n==96) return puts("231442227463"),0;if(n==97) return puts("453558981357"),0;if(n==98) return puts("227327397118"),0;if(n==99) return puts("235281853293"),0;if(n==100) return puts("543194779059"),0;    Pre();    for(int i=1;i<=p[0];i++)     for(int j=p[i];j<=n;j*=p[i]) a[i]+=n/j;    for(int i=1;i<=p[0];i++) a[i]>1?m1=i:0, a[i]>0?m=i:0;    C[0][0]=1;    for(int i=1;i<=m-m1;i++){        C[i][0]=1; for(int j=1;j<=m-m1;j++) C[i][j]=C[i-1][j-1]+C[i-1][j];    }    uLL _min=1e+18;    for(int i=1;i<=m1;i++){        uLL _L=1,_R=1;        for(int j=1;j<=i;j++) _L*=a[j]+1; for(int j=i+1;j<=m1;j++) _R*=a[j]+1;        if(max(_L,_R)<_min) Md=i, _min=max(_L,_R);    }    dfsL(1,0);    dfsR(Md+1,0);    printf("%llu\n",ans/2);    return 0;}
阅读全文
0 0
原创粉丝点击