#10202. 「一本通 6.2 练习 5」樱花
题意很简单,就是求给你的那个式子中(x,y)的解得数量。
但是做起来没那么容易了,基本思路是这样的:
需要想办法对式子进行整理,进而得到可以解决问题的式子。
首先把原式进行通分,得到
进行十字相乘,得到 n!(x+y)=xy ;
移项,得n!(x+y)-xy=0;
两边同时加上(n!)2,得到(n!)2-n!(x+y)-xy=(n!)2;
对其进行因式分解,得到(n!-x)(n!-y)=(n!)2;
令a=(n!-x),b=(n!-y),式子变为 ab=(n!)2;
要求组合(x,y)的种数,即变成了求(n!)2 的因子a的种数,(n!是确定的,那么知道了a的种类数,就知道了b的种类数),
(n!)2 的因子想到唯一分解定理:n!=p1a1+p2a2+......+pnan ;那么(n!)2=ab=p12a1+p22a2+......+pn2an ;
唯一分解定理中关于因子的个数有cnt=(2×a1+1)×(2×a2+1)×...×(2×an+1) ;
问题最后就转化成了求(n!)2的因子的个数。
因为pn为质数,如果暴力求肯定会超时,所以需要素数筛来解决。
因为n!的每个质因子都不超过n,所以我们可以打表预处理1−n内所有质数p,再考虑n!内一共有多少个质因子p。
唯一分解定理讲解:唯一分解定理
素数筛讲解:素数筛法讲解
代码如下:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 using namespace std; 5 typedef long long ll; 6 const ll mod=1e9+7; 7 const int maxn=1e6+7; 8 int prime[maxn]; 9 bool isp[maxn]; 10 int cnt; 11 void makeprime()//预处理素数表 12 { 13 cnt=0; 14 memset(isp,true,sizeof(isp)); 15 for(int i=2;i<=maxn;i++) 16 { 17 if(isp[i]) 18 { 19 prime[++cnt]=i; 20 } 21 for(int j=1;j<=cnt;j++) 22 { 23 if(i*prime[j]>maxn) 24 break; 25 isp[i*prime[j]]=false; 26 if(i%prime[j]==0) 27 break; 28 } 29 } 30 return ; 31 } 32 int num[maxn];//用来记录1-n!中每个素数出现的次数 33 void makenum(int x)//得到次1-n!中每个素数出现的次数 34 { 35 for(int i=1;prime[i]*prime[i]<=x;i++) 36 { 37 if(x%prime[i]==0) 38 { 39 while(x%prime[i]==0) 40 { 41 num[prime[i]]++; 42 x/=prime[i]; 43 } 44 } 45 } 46 if(x>1) 47 num[x]++; 48 } 49 int main() 50 { 51 ll n; 52 cin>>n; 53 memset(num,0,sizeof(num)); 54 makeprime(); 55 for(int i=1;i<=n;i++)//这里每一个都要处理,因为是n!不是一个数n 56 { 57 makenum(i); 58 } 59 ll ans=1; 60 for(int i=1;i<=n;i++)//唯一分解定理的结论 61 { 62 ans=ans*((ll)num[i]*2+1)%mod; 63 } 64 printf("%lld",ans); 65 return 0; 66 }