题目传送门:https://www.luogu.org/problem/show?pid=1445
题目分析:这题我先自己推导了一遍,用了一种很麻烦的推法,后来发现题解的做法比我的快好多。
我自己的推导:
求:
1x+1y=1n!
xyx+y=n!
不妨令
k=gcd(x,y),x=ak,y=bk
:
原式化为:
abka+b=n!
由于
a,b
互质,
ab
与
a+b
也互质,不妨令
k=u(a+b)
,则有:
ab=n!u
而最开始的式子中:
x=a(a+b)u,y=b(a+b)u
令
n!u=pk11pk22……pkqq
,则对于
a
而言,它要么选某个质因子的最高次幂,要么不选(因为
还有题解的快速简便做法,比我的高到不知哪里去了(大概就是因式分解)。话说我初中奥数白学了
虽然推导方法不同,但最后代码都是一样的。用线性筛搞出所有素数,看看它在 n! 中出现几次(比如要求2在 n! 中的出现次数,就是 ⌊n2⌋+⌊n4⌋+⌊n8⌋+⌊n16⌋…… ),然后一通乱搞。
CODE:
#include<iostream>
#include<string>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<stdio.h>
#include<algorithm>
using namespace std;
const int maxn=1000100;
const long long M=1000000007;
typedef long long LL;
bool vis[maxn];
int prime[maxn];
int cur=0;
int num[maxn];
LL f[maxn];
int n;
void Linear_shaker()
{
for (int i=2; i<=n; i++)
{
if (!vis[i]) prime[++cur]=i;
for (int j=1; j<=cur && i*prime[j]<=n; j++)
{
vis[ i*prime[j] ]=true;
if ( !(i%prime[j]) ) break;
}
}
}
int main()
{
freopen("1445.in","r",stdin);
freopen("1445.out","w",stdout);
scanf("%d",&n);
Linear_shaker();
for (int i=1; i<=cur; i++)
{
LL x=prime[i];
while ( x<=(long long)n ) num[i]+=(n/x),x*=(long long)prime[i];
}
f[1]=(num[1]<<1)|1;
for (int i=2; i<=cur; i++) f[i]=f[i-1]*(long long)((num[i]<<1)|1)%M;
printf("%lld\n",f[cur]);
return 0;
}