「洛谷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;
}
posted @ 2020-10-30 21:35  zfio  阅读(97)  评论(1编辑  收藏  举报