「洛谷P1445」樱花
题目描述
分析
写一篇题解记一下,太感谢这道题了。通过这道题,我发现我写了好几个月的线性筛是错的。
首先,这题肉眼可见地要推柿子。
于是便有了:
\[\frac{1}{x} + \frac{1}{y} = \frac{1}{n!}
\]
\[x + y = \frac{xy}{n!}
\]
\[n!x + n!y = xy
\]
从这里就能看出来一点东西了,因为合法的情况两边都是正整数,所以\(n!y\)一定可以用\(x\)表示出来,设\(n!y=ax\)。
有
\[x(n! + a) = xy
\]
\[y=n!+a
\]
\[x=\frac{n!y}{a}
\]
\[x=\frac{n!(n!+a)}{a}
\]
\[x=\frac{(n!)^2}{a} + n!
\]
所以问题转化为求\(a|(n!)^2\)的\(a\)的个数,也就是\((n!)^2\)的因子的个数。
直接求显然会炸,考虑从阶乘的每一项入手,显然阶乘的每一项的贡献可以直接累加到每一个质因子上,平方就直接把每个质因子的贡献×2即可。
合法的\(a\),一定是从所有的质因子中选若干个出来乘起来得到的,每一个质因子有:选0个,选1个,选2个……选c[i]个(c[i]即为该质因子的总个数),共c[i]+1种选择。
于是,把所有的c[i]+1乘起来就是答案。
然后。
以上过程有手就行,但我就是连大样例都过不去。
调了半个多小时也没找出来有什么错,怀疑是自己NT式子推错了。
从你谷上嫖了一眼题解,发现思路挺对的,于是继续调。
最后,我实在没办法把所有中间变量都输出了一遍,然后发现...
我的线性筛TM居然把9筛成素数了...
我才发现我写了大半年的线性筛居然是错的!活到爆!那我这大半年的数学题都是怎么做的???
直接满脸黑人问号???
总之,感谢这道题,让我在距离CSP还有7天的时候发现我的数学是如此NB,也让我避免了CSP考场上真的需要用到线性筛的时候,发现怎么调都过不了样例的悲剧吧。
退役感 += INF
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6 + 10;
const int mod = 1e9 + 7;
int n;
int cnt;
int factor[maxn];
long long c[maxn];
int pcnt;
int prime[maxn];
bool vis[maxn];
void Prime() {
vis[1] = 1;
for (int i = 2; i <= n; ++i) {
if (!vis[i]) {
prime[++pcnt] = i;
}
for (int j = 1; j <= pcnt && i * prime[j] <= n; ++j) {
vis[i * prime[j]] = 1;
if (i * prime[j] > n) break;
}
}
}
int main() {
scanf("%d", &n);
Prime();
for (register int i = 2; i <= n; ++i) {
//一点小优化,如果这个数本身就是质数,就别再分解了,直接加上就行,也就是这里让我发现xxs是错的...
if (!vis[i]) { c[i]++; continue; }
int res = i;
for (register int j = 2; j * j <= res; ++j) {
while (!(res % j)) res /= j, c[j]++;
}
if (res > 1) c[res]++;
}
long long ans = 1;
int cnt = 0;
for (int i = 1; i <= n; ++i) {
if (!c[i]) continue;
ans = ans * (2 * c[i] + 1) % mod;
}
printf("%lld\n", ans);
return 0;
}
$$We're \; here \; to \; put \; a \; dent \; in \; the \; universe.$$