求不定方程

​1/x+1/y=1/n!
的正整数解(x,y)的数目。输入一个整数,输出一个整数,表示有多少对 (x,y) 满足题意。答案对10^9+7取模。

首先分式一定很不好弄,所以我们化分为整,得到(x+y)*n!=xy,移项得(x+y)*n!-xy=0,然后两边加上(n!)2,就变成了(n!)2-(x+y)*n!+xy=(n!)2,左边十字相乘变成(n!-x)*(n!-y),令A=(n!-x),B=(n!-y),则有A*B=(n!)2,然后由唯一分解定理,我们知道n!=p1a1*p2a2*p3a3*……pnan,其中pi为n!的素因子,所以(n!)2=(p1a1*p2a2*p3a3*……pnan2,所以(n!)2有(2*a1+1)*(2*a2+1)*……*(2*an+1)个因子,所以只需要素数筛一遍,然后每一个因子就对应了一个答案。

  但是在写完之后我却t了,在确定自己的素数筛没有问题之后,我在素数筛的代码后面和统计答案的代码后面分别输出了一个l和w,然后我发现当数据为1e6时l很快输出了,w却迟迟输出不了,我本来的意识中是素数并不多,O(n*cnt)(cnt为素数个数)的统计答案是没有什么问题的,可输出cnt的时候我却傻了,cnt是105级别的,不t才怪,于是学习了大佬的方法。具体见代码

代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #define ll long long
 4 using namespace std;
 5 const int mod=1e9+7;
 6 const int maxn=1000005;
 7 int n;
 8 ll ans=1;
 9 int a[maxn];
10 int v[maxn];//以前我的v数组都是bool类型的,只标记他是不是素数,现在是int类型
11 int prime[maxn],cnt; 
12 int tmp;
13 int main()
14 {
15     scanf("%d",&n);
16     for(int i=2;i<=n;++i)
17     {
18         if(!v[i])v[i]=i,cnt++,prime[cnt]=i;
19         for(int j=1;j<=cnt&&i*prime[j]<=n;++j)
20         {
21             v[i*prime[j]]=prime[j];//我们知道线性素数筛保证了每个合数被自己最小的素因子筛去,所以v数组就是记录了每个数最小的素因子,顺便的事,不会提高复杂度
22             if(i%prime[j]==0)break;
23         }
24     }
25     
26     for(int i=1;i<=n;++i)
27     {
28         for(int j=i;j>1;j/=v[j])//直接每次都除以自己的最小的素因子,不用枚举,把复杂度降到nlogn
29         {
30             a[v[j]]++,a[v[j]]%=mod;
31         }
32     }
33     for(int i=1;i<=n;++i)
34         ans*=(2*a[i]+1),ans%=mod;
35     printf("%lld\n",ans);
36     return 0;
37 }