• 【洛谷题解/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 
    #include 
    
    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;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    参考资料与后记

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

  • 相关阅读:
    【代码岁想录】哈希表刷题
    新唐NUC980使用记录:U-Boot & Linux 编译与烧录(基于SPI NAND)
    从NetSuite Payment Link杂谈财务自动化、数字化转型
    CentOS 8,凛冬将至
    C语言中volatile/register/const/static/extern/auto关键字的作用
    uni-app 5小时快速入门 5 目录结构
    PMP 11.27 考试倒计时15天!冲刺啦!
    OJ练习第170题——最大间距(桶算法)
    JVM内存模型
    MySQL性能优化Buffer Pool详细介绍
  • 原文地址:https://blog.csdn.net/lightningcs/article/details/126594447