搜索题。直接暴力枚举每个质数取几个。我们要判断一些数乘除最后是否等于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;
}