zoukankan      html  css  js  c++  java
  • 莫比乌斯反演与数论分块

    数学反演总结

    1 数论分块

    1.1 定理

    定理 1.1.1

    \[\left\lfloor\frac {\left\lfloor \frac{x}{b} \right\rfloor}{c} \right\rfloor=\left\lfloor\frac{x}{bc}\right\rfloor \]

    其中 \(x\in\R,b,c\in\N\)

    • 证明:设 \(x=kbc+r\),其中 \(r\in[0,bc)\) ,我们把 \(x\) 带入左边式子可以的得到:

      \[k+\left\lfloor\frac {\left\lfloor \frac{r}{b} \right\rfloor}{c} \right\rfloor \]

      因为:

      \[0\le \left\lfloor\frac {\left\lfloor \frac{r}{b} \right\rfloor}{c} \right\rfloor\le \left\lfloor\frac {r}{bc} \right\rfloor=0 \]

      所以我们可以得到:

      \[\left\lfloor\frac {\left\lfloor \frac{r}{b} \right\rfloor}{c} \right\rfloor=k \]

      显然,右边式子也等于 \(k\),所以结论成立。

    1.2 算法讲解

    其实数论分块(又被称为除法分块)是可以在 \(\sqrt n\) 的复杂度内算出:

    \[\sum\limits_{i=1}^n\lfloor \frac{n}i \rfloor \]

    这是因为我们注意到和式求和的部分的取值只有 \(2\sqrt n\) 中,证明这个结论只需要讨论 \(i\le \sqrt n\)\(i> \sqrt n\)​ 两种情况即可。

    一般的,对于:

    \[\sum\limits_{i=1}^n\lfloor \frac{n}{f(i)}\rfloor \]

    我们要求其值相等的左右边界,只需要让:

    \[\lfloor\frac{n}{f(l)}\rfloor=\lfloor\frac{n}{f(r)}\rfloor \]

    由数论分块的正确性可以得到:

    \[f(r)=\left\lfloor \frac{n}{\lfloor \frac{n}{f(l)}\rfloor}\right\rfloor \]

    我们求解 \(f(l)\) 并解方程解出 \(r\) 为多少即可得出数论分块区间。

    1.3 例题

    1.3.1 P2261 [CQOI2007]余数求和

    我们直接推式子:

    \[\sum\limits_{i=1}^nk\bmod i=\sum\limits_{i=1}^nk-\lfloor \frac ki\rfloor\times i=nk-\sum\limits_{i=1}^ni\lfloor\frac ik\rfloor \]

    可以应用数论分块,注意后面要特判是否等于 \(0\)

    代码:

    #include<bits/stdc++.h>
    #define dd double
    #define ld long double
    #define ll long long
    #define uint unsigned int
    #define ull unsigned long long
    #define N number
    #define M number
    using namespace std;
    
    const int INF=0x3f3f3f3f;
    
    template<typename T> inline void read(T &x) {
        x=0; int f=1;
        char c=getchar();
        for(;!isdigit(c);c=getchar()) if(c == '-') f=-f;
        for(;isdigit(c);c=getchar()) x=x*10+c-'0';
        x*=f;
    }
    
    inline ll calc(int l,int r){
        return 1ll*(r+l)*(r-l+1)/2;
    }
    
    ll ans=0,n,k;
    
    int main(){
        read(n);read(k);
        for(int i=1;i<=n;){
            int j;
            if(k/i>0) j=k/(k/i);
            else j=n;
            j=min((ll)j,n);
            ans+=(k/i)*calc(i,j);
            i=j+1;
        }
        printf("%lld\n",n*k-ans);
        return 0;
    }
    

    代码第 \(31\)\(32\) 行为特判。

    1.3.2 CF1485C Floor and Mod

    推式子:

    \[\left\lfloor \frac{a}{b} \right\rfloor=a\bmod b=a-\lfloor\frac{a}{b}\rfloor\times b\\ \Rightarrow \lfloor\frac{a}{b}\rfloor\times (b+1) =a\Rightarrow \lfloor\frac{a}{b}\rfloor=\frac{a}{b+1} \]

    所以我们只需要枚举 \(b\) ,同时统计有多少 \(a\)\(b+1\) 的倍数,这个数应该是 \(\frac{x}{b+1}\)

    但是需要注意的一点是,我们需要保证 \(\lfloor\frac{a}{b}\rfloor=\frac{a}{b+1}<b\) ,所以我们有 \(a<b^2+b\) ,所以上面这个式子应该变成:\(\frac{\min(x,b^2+b-1)}{b+1}\)

    我们根号分治并分开讨论,数论分块即可。复杂度为 \(O(\sqrt n)\)

    代码:

    #include<bits/stdc++.h>
    #define dd double
    #define ld long double
    #define ll long long
    #define int long long
    #define uint unsigned int
    #define ull unsigned long long
    #define N number
    #define M number
    using namespace std;
    
    const int INF=0x3f3f3f3f;
    
    template<typename T> inline void read(T &x) {
        x=0; int f=1;
        char c=getchar();
        for(;!isdigit(c);c=getchar()) if(c == '-') f=-f;
        for(;isdigit(c);c=getchar()) x=x*10+c-'0';
        x*=f;
    }
    
    int t;
    ll x,y;
    
    inline ll calc(ll x,ll y){
        ll ans=0;ll b=1;
        for(;b*b+b-1<=x&&b<=y;b++) ans+=(b*b+b-1)/(b+1);
        for(int i=b;i<=y;){
            int j=(x/(i+1)==0)?y:(x/(x/(i+1))-1);
            j=min((ll)j,y);
            ans+=(x/(i+1))*(j-i+1);
            i=j+1;
        }
        return ans;
    }
    
    signed main(){
        // freopen("my.in","r",stdin);
        // freopen("my.out","w",stdout);
        read(t);
        while(t--){
            read(x);read(y);
            printf("%lld\n",calc(x,y));
        }
        return 0;
    }
    

    2 莫比乌斯反演(进阶版)

    以前博主整理过一篇莫比乌斯反演,讲的比较基础,这里补充一下那篇博客里没有的内容。

    2.1 常用公式

    2.1.1 最大公因数,最小公倍数

    \[\sum\limits_{i=1}^n\sum\limits_{j=1}^m\text{lcm}(i,j)=\sum\limits_{i=1}^n\sum\limits_{j=1}^m\frac{ij}{\gcd(i,j)} \\ =\sum\limits_{i=1}^n\sum\limits_{j=1}^m\sum\limits_{d|i,d|j} [\gcd(\frac id,\frac jd)=1]\frac{ij}d\\ =\sum\limits_{d=1}^{\min(n,m)}d\sum\limits_{i=1}^{\left\lfloor \frac{n}{d} \right\rfloor}\sum\limits_{j=1}^{\left\lfloor \frac{m}{d} \right\rfloor}[\gcd(i,j)=1]ij\\ \]

    \(f(n,m)=\sum\limits_{i=1}^n\sum\limits_{j=1}^m[\gcd(i,j)=1]ij\),那么有:

    \[f(n,m)=\sum\limits_{i=1}^n\sum\limits_{i=1}^m\epsilon(\gcd(i,j))ij\\ =\sum\limits_{i=1}^n\sum\limits_{j=1}^m\sum\limits_{d|\gcd(i,j)}\mu(d)ij\\ =\sum\limits_{d=1}^{\min(n,m)}\mu(d)d^2\sum\limits_{i=1}^{\left\lfloor \frac{n}{d} \right\rfloor}\sum\limits_{j=1}^{\left\lfloor \frac{m}{d} \right\rfloor}ij\\ \]

    \(g(n,m)=\sum\limits_{i=1}^n\sum\limits_{j=1}^m ij\),显然,我们有 \(g(n,m)=\frac{(n+1)n}{2}\frac{(m+1)m}{2}\) ,可以 \(O(1)\) 计算,所以通过处理前缀和,\(f(n,m)\) 可以在 \(O(\sqrt n+\sqrt m)\) 的时间1复杂度算出,所以原式的复杂度可以做到 \(O(n+m+\sqrt n+\sqrt m)\)

    2.1.2 除数函数

    公式 2.1.2.1
    • \(\sigma_k(n)=\sum\limits_{d|n}d^k\)​​ ,令 \(id_k(n)=n^k\)​​ ,那么我们有 \(\sigma_k=id_k*I\)​​
    公式2.1.2.2
    • \(\sigma_0(xy)=\sum\limits_{i|x}\sum\limits_{j|y}[\gcd(i,j)=1]\)

      证明:我们考虑将 \(xy\)​​ 的每一个因子都与互质的 \(i,j\)​​ 意义映射。设 \(xy\)​​ 的因子为 \(k\)​​ ,设把 \(k\)​​ 唯一分解之后得到的式子为 \(\prod\limits_{i=1}^mp_i^{\alpha_i}\)​​​ 我们考虑每一个质数,设当前的质数为 \(p\)​​ ,设这个质数在 \(k\)​​ 中的指数为 \(\alpha\)​​ ,设在 \(x\)​​ 中的指数为 \(a\)​​ 设在 \(y\)​​ 中的指数为 \(b\)​​​ 。我们规定,如果 \(\alpha \le a\)​ ,那么令从 \(x\)​ 中拿取 \(p^{\alpha}\)​ ,否则就从 \(y\)​ 中拿取 \(p^{\alpha -a}\)​ 次方。这样,从 \(x\)​​ 中拿出来数就与从 \(y\)​​ 中拿出来的数互质。同时每一对互质的数,都可以映射到这么一个因子上。所以等式成立。证毕。这是一个重要的式子。

    定理 2.1.2.1
    • 除数函数是积性函数。

      证明:如果 \(x,y\) 互质,那么 \(xy\) 的一个因子 \(k\)\(k\) 一定可以分解成两个数,这两个数互质。也就是说,\(k\) 一部分来自 \(x\) ,一部分来自 \(y\)​ 。证毕。

      上面这个积性函数的性质,揭示我们除数函数也是可以线性筛的。不过我们有计算一些特殊除数函数前缀和更快的做法。

    公式 2.1.2.3
    • \(\sum\limits_{i=1}^n\sigma_0(i)=\sum\limits_{j=1}^n\left\lfloor \frac{n}{j} \right\rfloor\)

      证明:

      \[\sum\limits_{i=1}^n\sigma_0(i)=\sum\limits_{i=1}^n\sum\limits_{j=1}^i[j|i]=\sum\limits_{j=1}^n\sum\limits_{i=1}^{\left\lfloor \frac{n}{j} \right\rfloor}1=\sum\limits_{j=1}^n \left\lfloor \frac{n}{j} \right\rfloor \]

      整除分块即可。

    公式 2.1.2.4
    • \(\sum\limits_{i=1}^n\sum\limits_{j=1}^m\sigma_0(ij)=\sum\limits_{d=1}^{\min(n,m)}\mu(d)(\sum\limits_{x=1}^{\left\lfloor \frac{n}{d} \right\rfloor}\left\lfloor \frac{n}{xd} \right\rfloor)(\sum\limits_{y=1}^{\left\lfloor \frac{m}{d} \right\rfloor}\left\lfloor \frac{m}{yd} \right\rfloor)\)

      证明:

      \[\sum\limits_{i=1}^n\sum\limits_{j=1}^m\sigma_0(ij)=\sum\limits_{i=1}^n\sum\limits_{j=1}^m\sum\limits_{x|i}\sum\limits_{y|j}\epsilon(\gcd(x,y))\\ =\sum\limits_{x=1}^n\sum\limits_{y=1}^m \epsilon(\gcd(x,y)) \sum\limits_{i=1}^{\left\lfloor \frac{n}{x} \right\rfloor}\sum\limits_{j=1}^{\left\lfloor \frac{m}{y} \right\rfloor}1\\ =\sum\limits_{x=1}^n\sum\limits_{y=1}^m\sum\limits_{d|\gcd(x,y)}\mu(d)\left\lfloor \frac{n}{x} \right\rfloor\left\lfloor \frac{m}{y} \right\rfloor\\ =\sum\limits_{d=1}^{\min(n,m)}\sum\limits_{x=1}^{\left\lfloor \frac{n}{d} \right\rfloor}\sum\limits_{y=1}^{\left\lfloor \frac{m}{d} \right\rfloor}\mu(d)\left\lfloor \frac{n}{xd} \right\rfloor\left\lfloor \frac{m}{yd} \right\rfloor\\ =\sum\limits_{d=1}^{\min(n,m)}\mu(d)(\sum\limits_{x=1}^{\left\lfloor \frac{n}{d} \right\rfloor}\left\lfloor \frac{n}{xd} \right\rfloor)(\sum\limits_{y=1}^{\left\lfloor \frac{m}{d} \right\rfloor}\left\lfloor \frac{m}{yd} \right\rfloor) \]

    公式 2.1.2.5
    • \(\sigma_1(xy)=\sum\limits_{i|x}\sum\limits_{j|y}\frac{jx}{i}[\gcd(i,j)=1]\)​​

      证明:同样还是构造一一对应来证明,构造方法和上面证明 \(2.1.2.2\) 相同,设:

      \[x=\prod\limits_{i=1}^np_i^{\alpha_i},y=\prod\limits_{j=1}^np_j^{\beta_j}\\ i=\prod\limits_{j=1}^kp_{i_j}^{a_{i_j}},j=\prod_{i=1}^{n-k}p_{j_i}^{a_{j_i}} \]

      我们看 \(\frac{jx}i\)​ 的值表示出来是多少,我们发现这个值是:

      \[\prod\limits_{j=1}^k p_{i_j}^{\alpha_{i_j}-a_{i_j}}\times \prod\limits_{i=1}^{n-k}p_{j_i}^{\alpha_{j_i}+a_{j_i}} \]

      这个 \(i,j\)​ 对应的因子是 \(\prod_{j=1}^kp_{i_j}^{a_{i_j}}\prod_{p_{j_i}}^{n-k}p_{j_i}^{\alpha_{j_i}+a_{j_i}}\)​,不难发现,这个因子与上面相比,右边相同,左边相乘是 \(x\)​​​ ,所以这两个因子是一一对应的。显然这个式子是正确的。

    公式 2.1.2.6
    • \(\sum\limits_{i=1}^n\sigma_1(i)=\sum\limits_{i=1}^ni\left\lfloor \frac{n}{i} \right\rfloor\)

      证明:

      \[\sum\limits_{i=1}^n\sigma_1(i)=\sum\limits_{i=1}^n\sum\limits_{j=1}^ij[j|i]=\sum\limits_{j=1}^n\sum\limits_{i=1}^{\left\lfloor \frac{n}{j} \right\rfloor}j=\sum\limits_{i=1}^nj\left\lfloor \frac{n}{j} \right\rfloor \]

    公式 2.1.2.7
    • \(\sum\limits_{i=1}^n\sum\limits_{j=1}^n\sigma_1(ij)=\sum\limits_{d=1}^n\mu(d)d(\sum\limits_{i=1}^{\left\lfloor \frac{n}{d} \right\rfloor}\sigma_1(i))^2\)

      证明:

      \[\sum\limits_{i=1}^n\sum\limits_{j=1}^n\sigma_1(ij)=\sum\limits_{i=1}^n\sum\limits_{j=1}^n\sum\limits_{x|i}\sum\limits_{y|j}\frac{jx}{y}[\gcd(x,y)=1]\\ =\sum\limits_{x=1}^{n}\sum\limits_{y=1}^n\sum\limits_{i=1}^{\left\lfloor \frac{n}{x} \right\rfloor}\sum\limits_{j=1}^{\left\lfloor \frac{n}{y} \right\rfloor}jx\times \epsilon(\gcd(x,y))\\ =\sum\limits_{d=1}^n\mu(d)d \sum\limits_{x=1}^{\left\lfloor \frac{n}{d} \right\rfloor}\sum\limits_{y=1}^{\left\lfloor \frac{n}{d} \right\rfloor}\sum\limits_{i=1}^{\left\lfloor \frac{n}{xd} \right\rfloor}\sum\limits_{j=1}^{\left\lfloor \frac{n}{yd} \right\rfloor}jx\\ =\sum\limits_{d=1}^{n}\mu(d)d\sum\limits_{x=1}^{\left\lfloor \frac{n}{d} \right\rfloor}x\left\lfloor \frac{n}{xd} \right\rfloor\sum\limits_{y=1}^{\left\lfloor \frac{n}{d} \right\rfloor}\sum\limits_{j=1}^{\left\lfloor \frac{n}{yd} \right\rfloor}j\\ =\sum\limits_{d=1}^{n}\mu(d)d\sum\limits_{x=1}^{\left\lfloor \frac{n}{d} \right\rfloor}\sigma_1(x)\sum\limits_{y=1}^{\left\lfloor \frac{n}{d} \right\rfloor}\sigma_1(y)\\ =\sum\limits_{d=1}^{n}\mu(d)d(\sum\limits_{i=1}^{\left\lfloor \frac{n}{d} \right\rfloor}\sigma_1(i))^2 \]

    公式 2.1.2.8
    • \(\sum\limits_{i=1}^n\mu^2(i)=\sum\limits_{i=1}^{\sqrt n}\mu(i)\times\left\lfloor \frac{n}{i^2} \right\rfloor\)

      这个公式需要构造来证明,具体证明过程请参照例题 \(2.2.4\)

    公式 2.1.2.9
    • \(\sum\limits_{i=1}^n\mu^2(i)\left\lfloor \sqrt{\frac{n}{i}} \right\rfloor\)​​

      这个东西的证明和上面类似,我们同样考虑构造。考虑 \(1\)\(n\) 内所有不能被完全平方数整除的数组成的集合 \(P\) ,那么 \(1\)\(n\) 内的每一个数都可以表示成 \(xy^2\) 的形式,其中 \(x\in P,y\le \sqrt{\frac nx}\),上面的式子其实等价于 \(\sum\limits_{p\in P}\left\lfloor \sqrt{\frac{n}{i}} \right\rfloor\)​,根据 \(y\) 的取值范围,不难发现这个式子的正确性。

    公式 2.1.2.10
    • \(\sum\limits_{i=1}^n\sum\limits_{j=1}^n[\gcd(i,j)=1]=\sum\limits_{d=1}^n\mu(d)\left\lfloor \frac{n}{d} \right\rfloor=2S_{\phi}(\left\lfloor \frac{n}{d} \right\rfloor)-1\)

      证明:

      这里只证明后面的那个式子。

      \(f(n)=\sum\limits_{i=1}^n\sum\limits_{j=1}^n[\gcd(i,j)=1],g(n)=\sum\limits_{i=1}^n\sum\limits_{j=1}^i[\gcd(i,j)=1]\),那么 \(g(n)=S_{\phi}(i)\),那么容易验证有:\(f(n)=2g(n)-1\) ,减 \(1\) 是因为 \((1,1)\) 被算重了。

    公式 2.1.2.11
    • \(\prod\limits_{i=1}^n\prod\limits_{j=1}^n\gcd^2(i,j)=(\prod\limits_{i=1}^nd^{S_{\phi}(\left\lfloor \frac{n}{d} \right\rfloor)})\)

      证明:

      \[\prod\limits_{i=1}^n\prod\limits_{j=1}^n\gcd{^2}(i,j)=\prod\limits_{i=1}^nd^{\sum\limits_{i=1}^n\sum\limits_{j=1}^n[\gcd(i,j)=d]}\\ =\prod\limits_{i=1}^nd^{\sum\limits_{i=1}^{\left\lfloor \frac{n}{d} \right\rfloor}\sum\limits_{j=1}^{\left\lfloor \frac{n}{d} \right\rfloor}\gcd(i,j)=1} \]

      由公式 \(2.1.2.10\) 可以知道,该公式成立。

    2.2 例题

    上面的每一个公式按顺序依次标号。

    2.2.1 洛谷P3935

    运用上面公式 \(2.1.2.3\)​​​ 即可。

    #include<bits/stdc++.h>
    #define dd double
    #define ld long double
    #define ll long long
    #define uint unsigned int
    #define ull unsigned long long
    #define N number
    #define M number
    using namespace std;
    
    const int INF=0x3f3f3f3f;
    const int mod=998244353;
    
    template<typename T> inline void read(T &x) {
        x=0; int f=1;
        char c=getchar();
        for(;!isdigit(c);c=getchar()) if(c == '-') f=-f;
        for(;isdigit(c);c=getchar()) x=x*10+c-'0';
        x*=f;
    }
    
    ll l,r;
    
    inline int Solve(ll k){
        if(k<1) return 0;
        int ans=0;
        for(ll i=1,j;i<=k;i=j+1){
            j=k/(k/i);
            ans=1ll*(ans+1ll*k/i*(j-i+1)%mod)%mod;
        }
        return ans;
    }
    
    int main(){
        read(l);read(r);
        printf("%d\n",((Solve(r)-Solve(l-1))%mod+mod)%mod);
        return 0;
    }
    

    2.2.2 洛谷P3327

    公式 \(2.1.2.4\)

    代码:

    #include<bits/stdc++.h>
    #define dd double
    #define ld long double
    #define ll long long
    #define uint unsigned int
    #define ull unsigned long long
    #define N 50010
    #define M number
    using namespace std;
    
    const int INF=0x3f3f3f3f;
    
    template<typename T> inline void read(T &x) {
        x=0; int f=1;
        char c=getchar();
        for(;!isdigit(c);c=getchar()) if(c == '-') f=-f;
        for(;isdigit(c);c=getchar()) x=x*10+c-'0';
        x*=f;
    }
    
    bool NotPrime[N];
    int Prime[N],tail,Mu[N],SumMu[N];
    
    inline void Getmu(int n){
        NotPrime[1]=1;Mu[1]=1;
        for(int i=2;i<=n;i++){
            if(!NotPrime[i]) Prime[++tail]=i,Mu[i]=-1;
            for(int j=1;j<=tail&&i*Prime[j]<=n;j++){
                int k=i*Prime[j];NotPrime[k]=1;
                if(i%Prime[j]==0){Mu[k]=0;break;}
                else Mu[k]=Mu[i]*Mu[Prime[j]];
            }
        }
        for(int i=1;i<=n;i++) SumMu[i]=SumMu[i-1]+Mu[i];
    }
    
    ll f[N];
    
    inline ll Get(int k){
        ll ans=0;
        for(int i=1,j;i<=k;i=j+1){
            j=k/(k/i);ans+=(k/i)*(j-i+1);
        }
        return ans;
    }
    
    inline ll Solve(int n,int m){
        int minn=min(n,m);
        ll ans=0;
        for(int i=1,j;i<=minn;i=j+1){
            int j1=n/(n/i),j2=m/(m/i);j=min(j1,j2);
            ans+=(SumMu[j]-SumMu[i-1])*f[n/i]*f[m/i];
        }
        return ans;
    }
    
    int t;
    
    int main(){
        read(t);Getmu(50000);
        for(int i=1;i<=50000;i++) f[i]=Get(i);
        while(t--){
            int n,m;read(n);read(m);
            printf("%lld\n",Solve(n,m));
        }
        return 0;
    }
    

    2.2.3 51nod1220

    公式 \(2.1.2.7\)

    代码:

    #include<bits/stdc++.h>
    #define dd double
    #define ld long double
    #define ll long long
    #define int long long
    #define uint unsigned int
    #define ull unsigned long long
    #define N 1000010
    #define M number
    using namespace std;
    
    const int INF=0x3f3f3f3f;
    const int mod=1e9+7;
    
    template<typename T> inline void read(T &x) {
        x=0; int f=1;
        char c=getchar();
        for(;!isdigit(c);c=getchar()) if(c == '-') f=-f;
        for(;isdigit(c);c=getchar()) x=x*10+c-'0';
        x*=f;
    }
    
    map<int,ll> Map,f;
    const ll inv2=500000004;
    
    inline ll CalcSumSigma_1(int n){
        ll nowans=0;
        for(int i=1,j;i<=n;i=j+1){
            j=n/(n/i);
            nowans=(nowans+1ll*(n/i)*(i+j)%mod*(j-i+1)%mod*inv2%mod)%mod;
        }
        return nowans;
    }
    
    int Prime[N],F[N],SumF[N],tail,MAXN;
    bool NotPrime[N];
    
    inline void GetSumF(){
        int n=1000000;MAXN=n;
        NotPrime[1]=1;F[1]=1;
        for(int i=2;i<=n;i++){
            if(!NotPrime[i]) Prime[++tail]=i,F[i]=-i;
            for(int j=1,k;j<=tail&&(k=i*Prime[j])<=n;j++){
                NotPrime[k]=1;
                if(i%Prime[j]==0){F[k]=0;break;}
                else F[k]=F[Prime[j]]*F[i]%mod;
            }
        }
        for(int i=1;i<=n;i++) SumF[i]=(SumF[i-1]+F[i])%mod;
    }
    
    inline ll CalcSumF(int n){
        if(n<=MAXN) return SumF[n];
        if(f[n]) return f[n];
        ll now=(n>=1);
        for(int i=2,j;i<=n;i=j+1){
            j=n/(n/i);
            now=(now-1ll*CalcSumF(n/i)*(i+j)%mod*(j-i+1)%mod*inv2%mod)%mod;
        }
        f[n]=now;
        return now;
    }
    
    int n;
    
    inline void GetSumSigma_1(){
        for(int i=1,j;i<=n;i=j+1){
            j=n/(n/i);
            ll val=CalcSumSigma_1(n/i)%mod;
            Map[n/i]=val*val%mod;
        }
    }
    
    inline void PreWork(){
        GetSumSigma_1();GetSumF();
    }
    
    signed main(){
        // freopen("my.in","r",stdin);
        // freopen("my.out","w",stdout);
        read(n);
        PreWork();
        // cout<<"here\n";
        // for(int i=1;i<=100;i++){
        //     printf("%lld\n",SumF[i]);
        // }
        ll ans=0;
        for(int i=1,j;i<=n;i=j+1){
            j=n/(n/i);
            // printf("i:%lld\n",i);
            // cout<<Map[n/i]<<endl;
            // cout<<(CalcSumF(j)-CalcSumF(i-1))<<endl;
            ans=(ans+1ll*(CalcSumF(j)-CalcSumF(i-1))*Map[n/i]%mod)%mod;
        }
        printf("%lld\n",(ans%mod+mod)%mod);
        return 0;
    }
    

    2.2.4 洛谷P4318

    不难发现,答案具有可二分性。我们规定,如果一个数不能被完全平方数整除,则称其合法,否则称其不合法。那么 \(n\) 以内的合法的数一共有多少呢?不难发现,答案应该是:

    \[\sum\limits_{i=1}^n\mu^2(i) \]

    即为 \(1\)\(n\) 中所有 \(\mu(x)\) 不为 \(0\) 的数。

    我们考虑用容斥来计算这个东西,不难发现这个东西其实也是可以这样计算的:

    \(0\) 个质数的平方的倍数减去含 \(1\) 个质数的平方的倍数加上含 \(2\) 个质数平方的倍数......,考虑莫比乌斯函数的定义,我们发现上面这个式子其实也是:

    \[\sum\limits_{i=1}^{i\times i\le n}\mu(i)\times\left\lfloor \frac{n}{i^2} \right\rfloor \]

    所以我们就可以二分这个答案,然后在 \(O(\sqrt n)\) 的时间复杂度内判断合不合法。

    代码:

    #include<bits/stdc++.h>
    #define dd double
    #define ld long double
    #define ll long long
    #define uint unsigned int
    #define ull unsigned long long
    #define N 60010
    #define M number
    using namespace std;
    
    const int INF=0x3f3f3f3f;
    
    template<typename T> inline void read(T &x) {
        x=0; int f=1;
        char c=getchar();
        for(;!isdigit(c);c=getchar()) if(c == '-') f=-f;
        for(;isdigit(c);c=getchar()) x=x*10+c-'0';
        x*=f;
    }
    
    int Prime[N],tail,Mu[N];
    bool NotPrime[N];
    
    inline void PreWork(int n){
        NotPrime[1]=1;Mu[1]=1;
        for(int i=2;i<=n;i++){
            if(!NotPrime[i]) Prime[++tail]=i,Mu[i]=-1;
            for(int j=1,k;j<=tail&&(k=i*Prime[j])<=n;j++){
                NotPrime[k]=1;
                if(i%Prime[j]==0) break;
                else Mu[k]=-Mu[i];
            }
        }
    }
    
    int t;
    
    inline bool Check(int mid,int k){
        int res=0;
        for(ll i=1;i*i<=mid;i++){
            res=res+Mu[i]*(mid/(i*i));
        }
        return res>=k;
    }
    
    int main(){
        // freopen("my.in","r",stdin);
        // freopen("my.out","w",stdout);
        PreWork(60000);
        read(t);
        while(t--){
            ll k;read(k);
            ll l=k,r=2*k;
            while(l<r){
                // cout<<"l"<<" "<<l<<endl;
    
                int mid=(l+r)>>1;
                if(Check(mid,k)) r=mid;
                else l=mid+1;
            }
            printf("%lld\n",l);
        }
    }
    

    2.2.5 SP5971 LCMSUM - LCM Sum

    要求计算 \(\sum_{i=1}^nlcm(i,n)\) ,我们尝试化简这个东西:

    \[\sum\limits_{i=1}^nlcm(i,n)=\sum\limits_{i=1}^n\frac{in}{\gcd(i,n)}=\sum\limits_{i=1}^n\sum\limits_{d|i,d|n}[\gcd(\frac di,\frac nd)=1]\times \frac{in}{d}\\ =\sum\limits_{d|n}\sum\limits_{i=1}^{\left\lfloor \frac{n}{d} \right\rfloor}in[\gcd(i,\frac nd)=1] \]

    我们令 \(g(x)=\sum\limits_{i=1}^x[\gcd(i,x)=1]\times i\) 即在 \(1\)\(x\) 总所有与 \(x\) 互质的数的个数,因为 \(\gcd(i,n)=1\Leftrightarrow\gcd(n-i,i)\) ,所以互质的数总是两两一对,且和为 \(n\)

    所以这个和应该是 \(\frac{\phi(x)x}{2}\)

    所以上面那个式子可以化简为:

    \[n\sum\limits_{d|n}\frac{\phi(d)d}{2} \]

    我们可以用 \(n\log n\) 的时间复杂度完成这个事情。

    这个地方有一点不太严谨,当 \(d=1\) 的时候注意 \(g(1)=1\),这个是个特殊的。

    #include<bits/stdc++.h>
    #define dd double
    #define ld long double
    #define ll long long
    #define uint unsigned int
    #define ull unsigned long long
    #define N 1000100
    #define M number
    using namespace std;
    
    const int INF=0x3f3f3f3f;
    
    template<typename T> inline void read(T &x) {
        x=0; int f=1;
        char c=getchar();
        for(;!isdigit(c);c=getchar()) if(c == '-') f=-f;
        for(;isdigit(c);c=getchar()) x=x*10+c-'0';
        x*=f;
    }
    
    int Prime[N],tail,Phi[N];
    ll g[N],f[N];
    bool NotPrime[N];
    
    inline void PreWork(int n){
        NotPrime[1]=1;Phi[1]=1;
        for(int i=2;i<=n;i++){
            if(!NotPrime[i]) Prime[++tail]=i,Phi[i]=i-1;
            for(int j=1,k;j<=tail&&(k=i*Prime[j])<=n;j++){
                NotPrime[k]=1;
                if(i%Prime[j]==0){
                    Phi[k]=Phi[i]*Prime[j];break;
                }
                else Phi[k]=Phi[i]*Phi[Prime[j]];
            }
        }
        // for(int i=1;i<=5;i++) printf("%d ",Phi[i]);puts("");
        g[1]=1;
        for(int i=2;i<=n;i++) g[i]=1ll*Phi[i]*i/2;
        // for(int i=1;i<=5;i++) printf("%lld ",g[i]);puts("");
        for(int i=1;i<=n;i++)
            for(int j=i;j<=n;j+=i) f[j]+=g[i];
        for(int i=1;i<=n;i++) f[i]*=i;
    }
    
    int t,n;
    
    int main(){
        // freopen("my.in","r",stdin);
        // freopen("my.out","w",stdout);
        PreWork(1000000);
        read(t);
        while(t--){
            read(n);printf("%lld\n",f[n]);
        }
    }//
    

    2.2.6 P3768 简单的数学题

    首先我们尝试化简式子:

    \[\sum\limits_{i=1}^n\sum\limits_{j=1}^nij\gcd(i,j)=\sum\limits_{k=1}^n\sum\limits_{k|i,i\le n}\sum\limits_{k|j,j\le n}ijk[\gcd(\left\lfloor \frac{k}{i} \right\rfloor,\left\lfloor \frac{k}{j} \right\rfloor)=1]\\ =\sum\limits_{k=1}^n\sum\limits_{i=1}^{\left\lfloor \frac{n}{k} \right\rfloor}\sum\limits_{j=1}^{\left\lfloor \frac{n}{k} \right\rfloor}ijk^3[\gcd(i,j)=1] \]

    \(g(n)=\sum_{i=1}^n\sum_{j=1}^nij[\gcd(i,j)=1]\),我们可以得到:

    \[g(n)=\sum\limits_{i=1}^ni\sum\limits_{j=1}^nj[\gcd(i,j)=1]=[n\ge 1]+\sum\limits_{i=2}^n\frac{\phi(i)i}{2} \]

    所以原来的式子我们可以化简为:

    \[\sum\limits_{k=1}^nk^3g(\left\lfloor \frac{n}{k} \right\rfloor) \]

    由于 \(n\)\(1e9\) 级别的,所以我们可以用杜教筛筛一下 \(g(n)\) 。然后用整除分块。因为杜教筛也是整除分块计算的,所以杜教筛外面套一个整除分块没有问题。

    莫比乌斯函数扩展

    莫比乌斯函数非卷积形式。

    对于数论函数和完全积性函数 \(t\)\(t(1)=1\) ,有以下等价式子:

    \[f(n)=\sum\limits_{i=1}^nt(i)g(\left\lfloor \frac{n}{i} \right\rfloor)\Leftrightarrow g(n)=\sum\limits_{i=1}^nt(i)\mu(i)f(\left\lfloor \frac{n}{i} \right\rfloor) \]

    • 证明:

      \[g(n)=\sum\limits_{i=1}^nt(i)\mu(i)f(\left\lfloor \frac{n}{i} \right\rfloor)\\ =\sum\limits_{i=1}^nt(i)\mu(i)\sum\limits_{j=1}^{\left\lfloor \frac{n}{i} \right\rfloor}t(j)g(\left\lfloor \frac{n}{ij} \right\rfloor)\\ =\sum\limits_{d=1}^n\sum\limits_{i|d} t(i)\mu(i)t(\frac{d}{i})g(\left\lfloor \frac{n}{d} \right\rfloor)\\ =\sum\limits_{d=1}^ng(\left\lfloor \frac{n}{d} \right\rfloor)t(d)\sum\limits_{i|d}t(i)\\ =\sum\limits_{d=1}^ng(\left\lfloor \frac{n}{d} \right\rfloor)t(d)\epsilon(d)\\ =g(n) \]

  • 相关阅读:
    Android获取两条线之间的夹角度数
    Android字体度量(FontMetrics)
    Android下如何计算要显示的字符串所占的宽度和高度
    Android 颜色渲染PorterDuff及Xfermode详解
    从输入URL到页面加载的全过程
    滚动优化
    常用的前端相关chrome插件
    DNS预解析prefetch
    资源预加载preload和资源预读取prefetch简明学习
    使用chrome开发者工具中的performance面板解决性能瓶颈
  • 原文地址:https://www.cnblogs.com/TianMeng-hyl/p/15674560.html
Copyright © 2011-2022 走看看