zoukankan      html  css  js  c++  java
  • 【spoj 5971】lcmsum

    全场都 AK 了就我爆 0 了


    题意

      (t) 组询问,每组询问给定 (n),求 (sumlimits_{k=1}^n [n,k])。其中 ([a,b]) 表示 (a)(b) 的最小公倍数。
      (tle 3 imes 10^5,space nle 10^6)

    题解

      怎么全世界都做过这题啊

      前一天晚上听林老师说今天 T1 是莫比乌斯反演,然后我就出了一身冷汗……我没做过几道莫反,推不出来式子会不会被 D 啊……
      然后到了今天……
      我自己用模板的方法(?)推了个奇怪的长式子,写完后以为解不了,于是扔一边了……
      后来才发现我 sb 了,其实可以解……
      我推的式子大概是这样 $$ans = sumlimits_{T=1}^n sumlimits_{g|T} frac{n (frac{T}{g}+lfloor frac{n}{T} floor frac{T}{g}) lfloor frac{n}{T} floor} {2} sigma(n) mu(frac{T}{g}) lfloorfrac{n}{T} floor$$
      ((sigma(n)) 表示 (n) 的约数个数)
      显然把 (frac{T}{g}) 提出来,只与 (frac{T}{g}) 有关的项都可以 (O(nlog n)) 预处理一下前缀和,查询的时候对 (lfloor frac{n}{T} floor) 整除分块即可。
      我才刚学莫比乌斯反演 (1e-18) 秒,就不能对我友好一点么
      这个式子的正确性我就懒得验证了,因为标程做法根本就不是莫反,是个简单数论……各位巨佬如果发现我这个式子有问题的话,还烦请指正 ( ext{ヽ(*^ー^)人(^ー^*)ノ})
      千万不能相信林老师预告的题目解法(flag)

      标程的做法大致是这样:

      很显然你没有看到任何莫反的痕迹,一个 (mu) 函数都没有。
      除了最后一行外,前面都很好理解。这里解释一下是怎么从倒数第二行 推出最后一行的(我大概就卡在这了):

      我们提出这部分:(sumlimits_{k=1}^{frac{n}{p}} [(k,frac{n}{p})=1])
      不难发现,它等于 (varphi(frac{n}{p}))
      然后我们考虑对于满足 ([(k,frac{n}{p})=1]) 的项 (k),把加 (1) 改成加 (k),即在 ([(k,frac{n}{p})=1]) 前面乘上 (k)
      这个好像不是很好求,但我们有这样一个经验:设 (age b),则 (gcd(a,b)=gcd(a,a-b))。运用到这里就是 (gcd(k,frac{n}{p}) = gcd(frac{n}{p}-k,frac{n}{p}))
      也就是说,若 ([(k,frac{n}{p})=1]),则有 ([(frac{n}{p}-k,frac{n}{p})=1])。即要累加的 (k) 是以 (frac{n}{p}) 为和成对出现的!
      这个性质就很好,我们可以把加 (k) 改成加 (frac{frac{n}{p}}{2}) 了。显然后者是个定值。
      所以我们简化倒数第二行式子得 $$ans = nsumlimits_{p|n}^{n} frac{frac{n}{p} imes varphi(frac{n}{p}) + [frac{n}{p}=1]} {2}$$ $$ans = nsumlimits_{p|n}^{n} frac{p imes varphi(p) + [p=1]}{2}$$
      ([p=1]) 是因为当 (p=1) 时只有 (1)(k),它并不能配对,也就不能当一对的平均数加。但由于加的 (k)(1),直接在分子补上 (1) 就行了。
      这就是标程做法的最后一行式子了。
      什么?你问后面那段式子能不能被 (2) 整除?你把除以 (2) 扩大到等号右边全局不就行了?(ans) 肯定是个整数吧。
      直到看了别人代码后我才发现后面那段式子一定被 (2) 整除……问了一下 scb 聚聚,他 1s 就证出来了,好强啊 ↓↓↓

        把 (varphi) 函数打个表就会发现,除了 (varphi(1))(varphi(2))(1) 以外,(varphi) 值都是偶数。
        考虑对 (varphi(x)(xgt 2))(x) 的奇偶性:
          若 (x) 是奇数,它至少有一个奇数因子 (y),所以计算 (varphi(x)) 时会乘一次 (frac{y-1}{y}),而 (y-1) 是偶数,所以 (varphi(x)) 是偶数。
          若 (x) 是偶数,它会被分解成 (2^z imes y),显然 (y) 是奇数。当 (y=1) 时,(varphi(x)=frac{x}{2}=2^{z-1}),是个偶数;当 (y) 为其它奇数时,因为 (varphi) 是积性函数,所以 (varphi(x) = varphi(2^z) varphi(y)),而 (varphi(y)) 是偶数,所以 (varphi(x)) 是偶数。
        所以当上述式子 (pgt 2) 时,(varphi(p)) 是偶数且 ([p=1]=0),故分子是偶数,可以被 (2) 整除。
        当上述式子 (p=2) 时,(p) 是偶数且 ([p=1]=0),故分子是偶数。
        当上述式子 (p=1) 时,(p imes varphi(p)=1)([p=1]=1),故分子是 (2),可以被 (2) 整除(其实也很显然除完后就是 (k=1))。

      预处理 (varphi) 即可。复杂度 (O(qlog n))

    #include<bits/stdc++.h>
    #define ll long long
    #define N 1000000
    using namespace std;
    inline int read(){
    	int x=0; bool f=1; char c=getchar();
    	for(;!isdigit(c); c=getchar()) if(c=='-') f=0;
    	for(; isdigit(c); c=getchar()) x=(x<<3)+(x<<1)+(c^'0');
    	if(f) return x; return 0-x;
    }
    int t,mx=0,cnt,a[N+5];
    ll phi[N+5],pri[N+5],ans[N+5];
    bool vis[N+5];
    void init(){
        phi[1]=1;
        for(int i=2;i<=N;i++){
            if(!vis[i]) pri[++cnt]=i, phi[i]=i-1;
            for(int j=1; j<=cnt && i*pri[j]<=N; j++){
                vis[pri[j]*i]=1;
                if(i%pri[j]==0){
    				phi[i*pri[j]] = phi[i] * pri[j];
                    break;
                }
                phi[i*pri[j]] = phi[i] * (pri[j]-1);
            }
        }
    }
    int main(){
        init();
        t=read();
        for(int i=1; i<=t; i++) mx = max(mx, a[i]=read());
        for(int i=1; i<=mx; i++)
            for(int j=1; i*j<=mx; j++)
                ans[i*j] += (1ll * phi[i] * i + (i==1)) >> 1;
        for(int i=1; i<=t; i++) printf("%lld
    ", 1ll * ans[a[i]] * a[i]);
        return 0;
    }
    

      做完这道题后我确信了一件事:我才刚学数论 (1e-18)

  • 相关阅读:
    实验一 GIT 代码版本管理
    DS博客作业05--查找
    DS博客作业04--图
    DS博客作业03--树
    DS博客作业02--栈和队列
    DS博客作业01-线性表
    C博客作业05--2019-指针
    C语言博客作业04--数组
    C语言博客作业03--函数
    python exp4 jieba+wordcloud
  • 原文地址:https://www.cnblogs.com/scx2015noip-as-php/p/spoj5971.html
Copyright © 2011-2022 走看看