[题解] 8.13考试 a
题目描述
给定T ∈ {1,2},以及一个正整数N。
当T=1时,求1/x + 1/y = 1/N 的正整数解(x,y) 的个数。
当T=2时,求1/x + 1/y = 1/N! 的正整数解(x,y) 的个数。
输入格式
两个整数T和N
输出格式
一个整数,表示解的个数
输入样例1
1 120
输出样例1
63
输入样例2
2 1439
输出样例2
102426508
数据范围
当T=1时,1<=n<=10^12
当T=2时,1<=n<=10^6
思路解析
首先我们考虑T=1的情况,式子可以化为:
(x+y) / x * y = 1/N => x * y = (x+y) * N => x * y = x * N + y * N => (y-N) * x = y * N
设 z = y-N => y = z+N ,所以 z * x = (z+N) * N => z * x = z * N + N * N => x = N + N * N / z
因为 x 是正整数,所以N * N 是z的倍数,于是解的个数实际上就是 N * N 的约数个数。
我们考虑暴力做法O(n^2)来思考怎么做。
可以发现,将n分解质因数后,n的约数个数=(sum[i]+1) * (sum[i+1]+1) * ... * (sum[i+...]+1)
其中,sum[i]表示质数i的个数。至于为什么应该很好想吧,考虑每个质数取0个,1个,2个...sum[i]个。还不懂的感性理解一下(不是
然后对于T=2的情况,因为N! = 1 * 2 * 3 * ... * N,我们就对于1-n每个数都分解一边质因数然后加起来再用上面的方法算就行了。
分解质因数什么的就不用说了吧。
赋上代码
#include<bits/stdc++.h> #define ll long long using namespace std; const int p=1e9+7; const int N=1e6+5; int t,cnt,z[N],sum[N],num[N]; bool flag[N]; ll n,ans=1; void shai(int len){ for(int i=2;i<=len;i++){ if(!flag[i]) z[++cnt]=i,num[i]=cnt; for(int j=1;j<=cnt;j++){ ll t=z[j]*i; if(t>len) break; flag[t]=1; if(i%z[j]==0) break; } } } int main(){ scanf("%d%lld",&t,&n); if(t==1){ shai((int)sqrt(n)); for(int i=1;i<=cnt;i++){ if(n==1) break; while(n%z[i]==0){ sum[i]++; n/=z[i]; } ans=(ans*(ll)(sum[i]*2+1))%p; } if(n>1) ans=(ans*(ll)3)%p; printf("%lld",ans); return 0; } else{ for(int i=2;i<=n;i++){ int m=i; for(int j=2;j*j<=m;j++){ if(m==1) break; while(m%j==0){ sum[j]++;m/=j; } } if(m>1) sum[m]++; } for(int i=1;i<=n;i++) if(sum[i]) ans=(ans*(ll)(sum[i]*2+1))%p; printf("%lld",ans); return 0; } return 0; }