洛谷 P1445 [Violet]樱花
首先数学推导
\[\frac{1}{x} + \frac{1}{y} = \frac{1}{n!} \\\frac{x+y}{xy} = \frac{1}{n!}\\(x+y)n! = xy \\xy-(x+y)n! = 0 \\xy - (x+y)n! + (n!)^2 = (n!)^2 \\(x-n!)(y-n!) = (n!)^2 \\
\]
于是乎我们只需要求 \((n!)^2\) 的约数个数即可
再由于约数定理,\(ans = \prod_{i=1}^{k}(s_i+1)\) ( 1~n 之间有k个质数)
得到答案为\(\prod_{i=1}^{k}(s_i+s_i+1)\)
统计答案时可以先用欧拉筛获得所有质数,并且获得每个合数的一个质因数,记录在\(pre\)中
然后从后往前扫,每获得一个质数就统计答案,每获得一个合数就拆分,把答案加到两个数里去,分别是\(pre[i]\)和\(i/pre[i]\)中
这样就\(O(n)\)出答案
[Code]
#include <bits/stdc++.h>
using namespace std;
int read(){
int x=0,flag=1; char c;
for(c=getchar();!isdigit(c);c=getchar()) if(c=='-') flag=-1;
for(;isdigit(c);c=getchar()) x=((x+(x<<2))<<1)+(c^48);
return x*flag;
}
const int mod=1e9+7;
const int N=1e6+10;
int n;
bool p[N];
int prime[N],cnt;
int pre[N],a[N];
void euler(){
p[0]=p[1]=1;
pre[0]=pre[1]=-1;
for(int i=2;i<=n;i++){
if(!p[i]){
prime[++cnt]=i;
pre[i]=i;
}
for(int j=1;j<=cnt&&prime[j]*i<=n;j++){
p[prime[j]*i]=1;
pre[prime[j]*i]=prime[j];
if(i%prime[j]==0) break;
}
}
}
int main() {
n=read();
euler();
long long ans=1;
for(int i=n;i>=2;i--){
a[i]++;
if(!p[i]) { ans=ans*(a[i]+a[i]+1)%mod; continue; }
a[pre[i]]+=a[i]; a[i/pre[i]]+=a[i];
a[i]=0;
}
printf("%lld\n",ans);
return 0;
}