【51nod 1189】阶乘分数——阶乘质因数分解
先对原式子进行一个变形:
1/n!=1/x+1/y=(x+y)/xy--->n!*(x+y)=xy
xy-(x+y)*n!=0--->xy-(x+y)*n!+n!2=n!2--->(x-n!)*(y-n!)=n!2
那么如果我们能够求出n!2的约数个数,对于每个约数加上n!即可作为x或y。
若n!=a1p1+a2p2+...+akpk,则n!的约数总数为∏(pi+1)。
因为是n!2,所以每个pi要乘上2.
因为对于每个约数a,都必将有唯一的一个b与它对应使得a*b=n!,所以如果不考虑x和y的大小和重复关系的话答案就是约数个数。
但是这里加上了限制条件,因此要除掉重复的部分,即需将答案加1除以2向下取整(加一是为了防止将完全平方数的平方根除去)
对于n!的质因数分解,则应该先把n以内的质数筛出,求出每个质数的阶数即可。
例:对10!分解质因数
10以内的质数有2,3,5,7.
2:10/2=5,10/4=2,10/8=1,阶数为2+5+1=8;
3:10/3=3,10/9=1,阶数为3+1=4;
5:10/5=2,阶数为2;
7:10/7=1,阶数为1;
所以10!=28*34*52*7.
代码:
1 #include<cstdio> 2 #include<algorithm> 3 typedef long long LL; 4 const LL mod=1e9+7; 5 const int N=1e6+10; 6 int n,prime[N],cnt=0; 7 bool vis[N]; 8 void make_prime(){ 9 for(int i=2;i<=n;i++){ 10 if(!vis[i])prime[++cnt]=i; 11 for(int j=1;j<=cnt&&i*prime[j]<=n;j++){ 12 vis[i*prime[j]]=1; 13 if(i%prime[j]==0)break; 14 } 15 } 16 } 17 LL ans=1,ni=(mod+1)/2; 18 int main(){ 19 scanf("%d",&n); 20 make_prime(); 21 for(int i=1;i<=cnt;i++){ 22 LL p1=0; 23 for(LL j=prime[i];j<=n;j*=prime[i])p1+=n/j; 24 ans=(ans*(2*p1+1)%mod)%mod; 25 } 26 printf("%lld",(ans+1ll)*ni%mod); 27 return 0; 28 }