求不定方程 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*……pnan)2,所以(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 ",ans); 36 return 0; 37 }