【洛谷题解/SDOI2012】P2303/SDOI2012 D1T1 Longge的问题

-放弃不难,但坚持很酷
-欢迎诸君感受思维与数学的魅力

原题链接:https://www.luogu.com.cn/problem/P2303
难度:提高+/省选-(省选D1T1)
涉及知识点:质因数分解、欧拉函数、思维

题意

求解 ∑ i = 1 n gcd ⁡ ( i , n ) , n ≤ 2 32 \sum\limits_{i=1}^{n}\gcd(i,n),n\leq2^{32} i=1ngcd(i,n),n232,简明的。

分析与解决

这是一道非常经典的推式子题,我们需要对原式进行一些推导和分析。笔者认为,这道题是很锻炼思维的。

由于笔者也是学习的粉兔的题解,所以本题解将完全复述一遍粉兔的思路,但会加以解释。

对于原式,我们将其转化为:
∑ j = 1 n ( j × ∑ i = 1 n [ gcd ⁡ ( i , n ) = j ] ) \sum\limits_{j=1}^{n}(j\times \sum\limits_{i=1}^{n}[\gcd(i,n)=j]) j=1n(j×i=1n[gcd(i,n)=j])
上式的意义为累加一个最大公约数值 j j j 1 ∼ n 1\sim n 1n 中该数值出现的次数的乘积。然后,将上式变换为:
∑ j = 1 n ( j × ∑ i = 1 n [ gcd ⁡ ( i / j , n / j ) = 1 ] ( j ∣ i , j ∣ n ) ) \sum\limits_{j=1}^{n}(j\times \sum\limits_{i=1}^{n}[\gcd(i/j,n/j)=1](j|i,j|n)) j=1n(j×i=1n[gcd(i/j,n/j)=1](ji,jn))
上式的意义是进行了一次数学上的变换,然后我们发先 j j j 乘的个数实际上就是 i / j i/j i/j n / j n/j n/j 互质的数的个数,所以我们可以改写为欧拉函数:
∑ j = 1 n ( j × φ ( n / j ) ( j ∣ n ) ) = ∑ j ∣ n ( j × φ ( n / j ) ) ① \sum\limits_{j=1}^{n}(j\times \varphi(n/j)(j|n))\\ =\sum\limits_{j|n}(j\times \varphi(n/j))① j=1n(j×φ(n/j)(jn))=jn(j×φ(n/j))
大多数的题解到这一步也就结束了,实际上到这一部分也就可以解题了,令因数个数为 k k k,复杂度为 O ( k n ) O(k\sqrt {n}) O(kn ),可以接受。

但是我们还可以对上式进行化简,我们设一个质数 p p p 表示 n n n 的质因子。 继续对 ① ① 式进行变换:
∑ j ∣ n ( n / j × φ ( j ) ) \sum\limits_{j|n}(n/j\times \varphi(j)) jn(n/j×φ(j))
然后展开为欧拉函数的公式:
∑ j ∣ n ( n / j × ( j × ∏ p ∣ j p − 1 p ) ) \sum\limits_{j|n}(n/j\times(j\times\prod\limits_{p|j} \frac{p-1}{p})) jn(n/j×(j×pjpp1))
j j j 和它的逆元抵消掉,得:
∑ j ∣ n ( n × ∏ p ∣ j p − 1 p ) = n × ∑ j ∣ n ∏ p ∣ j p − 1 p \sum\limits_{j|n}(n\times \prod\limits_{p|j}\frac{p-1}{p})\\ =n\times \sum\limits_{j|n}\prod_{p|j}\frac{p-1}{p} jn(n×pjpp1)=n×jnpjpp1

然后运用唯一分解定理,令 n = p 1 b 1 p 2 b 2 p 3 b 3 . . p k b k . n=p_1^{b_1}p_2^{b_2}p_3^{b_3}..p_k^{b_k}. n=p1b1p2b2p3b3..pkbk.,并定义 f i = p i − 1 p i \large f_i=\frac{p_i-1}{p_i} fi=pipi1

那么对于 n n n 的一个因子 j j j,可以将其表示为 j = p 1 c 1 p 2 c 2 p 3 c 3 . . . p k c k ( 0 ≤ c i ≤ b i ) j=p_1^{c_1}p_2^{c_2}p_3^{c_3}...p_k^{c_k}(0\leq c_i\leq b_i) j=p1c1p2c2p3c3...pkck(0cibi),那么 φ ( j ) = ∏ p ∣ j p − 1 p = ∏ i = 1 k f i ( c i > 0 ) \varphi(j)=\prod\limits_{p|j}\frac{p-1}{p}=\prod\limits_{i=1}^{k}f_i(c_i>0) φ(j)=pjpp1=i=1kfi(ci>0)。为什么要保证 c i > 0 c_i>0 ci>0,原因是显然的,如果 c i = 0 c_i=0 ci=0 j j j 的某个质因子不存在。

我们观察一类 ∏ i = 1 k f i ( c i > 0 ) \prod\limits_{i=1}^{k}f_i(c_i>0) i=1kfi(ci>0) 相等的因子 j , j ′ , j ′ ′ , . . . j,j',j'',... j,j,j′′,...,它们必须满足在 i i i 相等的情况下, c i c_i ci 同时大于或同时等于 0。因为如果前式相等,则说明这类数的质因子集合是相同的,只是可能 c i c_i ci ,即 p i p_i pi 的个数不同。基于该结论,我们可以推导出在这类数中,对于一个 p i p_i pi,要么同时出现,要么同时没有,也就是所谓的 c i c_i ci 同时大于或者同时等于 0。

那么这一类数有多少个呢?如果对于属于这类数的 j j j 有质因子 p q 1 , p q 2 , p q 3 , . . . p q g p_{q_1},p_{q_2},p_{q_3},...p_{q_g} pq1,pq2,pq3,...pqg,那么显然这类数 j j j 的答案为 ∏ i = 1 g f q i \prod\limits_{i=1}^{g}f_{q_i} i=1gfqi。令 b i b_i bi 为质因子 p i p_i pi 的指数,可以得到 j j j 的质因子个数为 ∏ i = 1 g b q i \prod\limits_{i=1}^{g}b_{q_i} i=1gbqi。那么就可以得到 j j j 对答案的贡献为 ∏ i = 1 g X q i \prod\limits_{i=1}^{g}X_{q_i} i=1gXqi X i = f i × b i X_i=f_i\times b_i Xi=fi×bi,也就是某一个 j j j 的某一个质因子的贡献乘上它的个数。

如果你能坚持看到这里,你一定不难发现每一个质因子的贡献都是独立的,那么最后我们枚举 n n n 的每一个质因子使用或者不适用,得到最终的答案 a n s ans ans 为:
a n s = n × ∏ i = 1 k ( X i + 1 ) ans=n\times \prod\limits_{i=1}^{k}(X_i+1) ans=n×i=1k(Xi+1)
为什么是 X i + 1 X_i+1 Xi+1 呢,举个例子,如果 n n n 只有 3 个质因子,那么 a n s ans ans n × ( 1 + X 1 + X 2 + X 3 + X 1 X 2 + X 1 X 3 + X 2 X 3 + X 1 X 2 X 3 ) n\times (1+X1+X2+X3+X1X2+X1X3+X2X3+X1X2X3) n×(1+X1+X2+X3+X1X2+X1X3+X2X3+X1X2X3),将其化简为多项式乘法就是 n × ( X 1 + 1 ) ( X 2 + 1 ) ( X 3 + 1 ) n\times(X1+1)(X2+1)(X3+1) n×(X1+1)(X2+1)(X3+1)。当然可以类比到质因数个数更多的情况。

如果你能看完这篇文章,我将发自内心地佩服你。

AC代码

#include <iostream>
#include <cstdio>

using namespace std;

typedef long long ll;

ll n;

ll solve ()
{
    ll ans = n;
    for (ll i = 2; i * i <= n; i++)
    {
        if (n % i == 0)
        {
            int b = 0;
            while (n % i == 0)
            { //分解质因数
                b++;
                n /= i;
            }
            ans /= i;
            ans *= b * i - b + i;
        }
    }
    if (n > 1)
    {
        ans /= n;
        ans *= n + n - 1;
    }
    return ans;
}

int main()
{
    cin >> n;
    cout << solve();
    return 0;
}

参考资料与后记

粉兔题解:https://www.cnblogs.com/PinkRabbit/p/8278728.html
本文可以视作粉兔题解的注释版(%%%%PinkRabbit),因为笔者在学习数论时其实是较为吃力的,所以我就写下了这篇注释性质的题解供自己以后复习使用也给大家参考。由于本文写作于深夜,如果本文中出现您不理解的地方或者是笔误的地方请联系笔者修改!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

oier_Asad.Chen

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值