分析:这道题对于我这种蒟蒻来说还是很有难度啊。
思路非常巧妙,既然不定方程要有有限个数解,那么这个肯定会对解有所限制,也就是本题中的正整数.这个时候我们要表示出方程中的一个根x,设z = n!,那么x=yz/(y-z),这样的话不能得到答案,我们要得到的式子一定是分母只能有乘积的形式,并且同一个字母不能同时在分子分母中出现,因为我们就是利用正整数的整除性来求解的,可以看出x和y都大于z,所以我们设y = z + d,带入,就消掉了y,可以得到x = z^2/d + z,因为x是正整数,所以z^2/d必须是整数,所以d是z^2的因子,那么我们只需要求出z^2有多少个约数就好了.
求约数的个数要用到乘法原理和线性筛,z可以表示为p1^k1 * p2^k2 * p3^k3*...*pn^kn这种形式,每个质因数可以选1到ki个或不选,而约数就是由不同的质因子通过相乘组合起来的,所以约数的个数就等于(k1 + 1)*(k2 + 1)*...*(kn + 1),而我们要求z^2的因子个数,总不可能直接平方吧......可以发现每个质因子的次数扩大了两倍,那么每个质因子就有2*ki + 1种选择,和上面一样直接乘法原理出答案.
因为z = n!,所以枚举1到n中的质数i的倍数,看i出现了几次,就能得到ki.
#include<iostream> #include<cstdio> #include<cstring> #include<queue> #include<cmath> using namespace std; const int mod = 1000000007; int prime[1000010], tot, cnt[1000010],n; bool vis[1000010]; long long ans = 1; void init() { for (int i = 2; i <= n; i++) { if (!vis[i]) prime[++tot] = i; for (int j = 1; j <= tot; j++) { if (prime[j] * i > n) break; vis[prime[j] * i] = 1; if (i % prime[j] == 0) break; } } } int main() { scanf("%d", &n); init(); for (int i = 1; i <= tot; i++) for (int j = prime[i]; j <= n; j += prime[i]) for (int k = j; k % prime[i] == 0; k /= prime[i]) cnt[i]++; for (int i = 1; i <= tot; i++) ans = (ans * 1LL * (cnt[i] * 2 + 1) % mod) % mod; printf("%lld ", ans); return 0; }