• 【模板】【系列】 杜教筛


    莫比乌斯反演的前置知识:https://www.cnblogs.com/yyc-jack-0920/p/10556351.html

    杜教筛可以在$O(n^{2/3})$的时间内求出积性函数的前缀和即$sumlimits_{i=1}^n f(i)$

    实现过程需要找到另一个积性函数$g$使得$f*g$为一个方便计算的函数

    $sum f*g=sumlimits_{i=1}^n sumlimits_{d|i} g(d)f(i/d) $

                    $=sumlimits_{d=1}^n g(d) sumlimits_{t=1}^{n/d} f(t)$

                    $=g(1)sumlimits_{i=1}^n f(i) + sumlimits_{d=2}^n g(d) sumlimits_{i=1}^{n/d} f(i)$

    设前缀和为$S(i)$ 即$g(1)S(n)=-sumlimits_{d=2}^n g(d) S(n/d)+sum f*g$

    这样就写成了一个数论分块的递归形式,复杂度可以证明(

    同时,由于杜教筛自带数论分块形式,因此在外面再套一层数论分块并不会影响复杂度

    luogu 4213 【模板】杜教筛:

    求$varphi$与$mu$的前缀和

    有结论:$varphi*1=id$、$mu *1 =[n=1]$ 直接套用公式即可

     1 #include<bits/stdc++.h>
     2 #define inf 2139062143
     3 #define MAXN 5001001
     4 #define MOD 1000000007
     5 #define ll long long
     6 #define ull unsigned long long
     7 #define rep(i,s,t) for(register int i=(s),i##end=(t);i<=i##end;++i)
     8 #define dwn(i,s,t) for(register int i=(s),i##end=(t);i>=i##end;--i)
     9 #define ren for(register int i=fst[x];i;i=nxt[i])
    10 #define Fill(a,b) memset(a,b,sizeof(a))
    11 #define pls(a,b) ((a+b)%MOD+MOD)%MOD
    12 #define mns(a,b) (((a)-(b))%MOD+MOD)%MOD
    13 #define mul(a,b) (1LL*(a)*(b)%MOD)
    14 #define pii pair<int,int>
    15 #define mp(a,b) make_pair(a,b)
    16 #define pb(i,x) vec[i].push_back(x)
    17 #define fi first
    18 #define se second
    19 using namespace std;
    20 inline ll read()
    21 {
    22     ll x=0;bool f=1;char ch=getchar();
    23     while(!isdigit(ch)) {if(ch=='-') f=0;ch=getchar();}
    24     while(isdigit(ch)) x=x*10+(ch^48),ch=getchar();
    25     return f?x:-x;
    26 }
    27 int lmt,ntp[MAXN],p[MAXN],tot;ll mu[MAXN],phi[MAXN];
    28 void mem(int n)
    29 {
    30     mu[1]=phi[1]=1;rep(i,2,n)
    31     {
    32         if(!ntp[i]) p[++tot]=i,mu[i]=-1,phi[i]=i-1;
    33         rep(j,1,tot) if(1LL*i*p[j]>n) break;
    34             else
    35             {
    36                 ntp[i*p[j]]=1;if(i%p[j]) mu[i*p[j]]=-mu[i],phi[i*p[j]]=phi[i]*phi[p[j]];
    37                 else {phi[i*p[j]]=phi[i]*p[j];break;}
    38             }
    39     }
    40     rep(i,1,n) mu[i]+=mu[i-1],phi[i]+=phi[i-1];
    41 }
    42 unordered_map<int,ll> ansm,ansp;
    43 ll smu(ll n,ll res=0)
    44 {
    45     if(n<=lmt) return mu[n];if(ansm[n]) return ansm[n];
    46     for(ll l=2,r;l<=n;l=r+1) r=n/(n/l),res+=smu(n/l)*(r-l+1);
    47     return ansm[n]=1LL-res;
    48 }
    49 ll sphi(ll n,ll res=0)
    50 {
    51     if(n<=lmt) return phi[n];if(ansp[n]) return ansp[n];
    52     for(ll l=2,r;l<=n;l=r+1) r=n/(n/l),res+=sphi(n/l)*(r-l+1);
    53     return ansp[n]=1LL*n*(n+1)/2-res;
    54 }
    55 int main()
    56 {
    57     int T=read(),n;mem(lmt=5000000);
    58     while(T--) {n=read();printf("%lld %lld
    ",sphi(n),smu(n));}
    59 }
    View Code

    51nod 1237 最大公约数之和V3

    题目大意:

    求$sumlimits_{i=1}^n sumlimits_{j=1}^{n} gcd(i,j)$

    思路:

    原式=$sumlimits_{d=1}^{n} d sumlimits_{i=1}^{n/d} sumlimits_{j=1}^{n/d} [gcd(i,j)==1]$

             $sumlimits_{d=1}^n d sumlimits_{i=1}^{n/d} mu(i) lfloorfrac{n}{id} floor lfloorfrac{n}{id} floor$

        $sumlimits_{g=1}^n lfloorfrac{n}{g} floor lfloorfrac{n}{g} floor sumlimits_{d|g} mu(d)*frac{g}{d}$

        $sumlimits_{g=1}^n lfloorfrac{n}{g} floor lfloorfrac{n}{g} floor cdot varphi(g)$

    数论分块+杜教筛求欧拉函数前缀和即可

     1 #include<bits/stdc++.h>
     2 #define inf 2139062143
     3 #define MAXN 5001001
     4 #define MOD 1000000007
     5 #define ll long long
     6 #define ull unsigned long long
     7 #define rep(i,s,t) for(register int i=(s),i##end=(t);i<=i##end;++i)
     8 #define dwn(i,s,t) for(register int i=(s),i##end=(t);i>=i##end;--i)
     9 #define ren for(register int i=fst[x];i;i=nxt[i])
    10 #define Fill(a,b) memset(a,b,sizeof(a))
    11 #define pls(a,b) (a+b)%MOD
    12 #define mns(a,b) (a-(b)+MOD)%MOD
    13 #define mul(a,b) (1LL*(a)*(b)%MOD)
    14 #define pii pair<int,int>
    15 #define mp(a,b) make_pair(a,b)
    16 #define pb(i,x) vec[i].push_back(x)
    17 #define fi first
    18 #define se second
    19 using namespace std;
    20 inline ll read()
    21 {
    22     ll x=0;bool f=1;char ch=getchar();
    23     while(!isdigit(ch)) {if(ch=='-') f=0;ch=getchar();}
    24     while(isdigit(ch)) x=x*10+(ch^48),ch=getchar();
    25     return f?x:-x;
    26 }
    27 int ntp[MAXN],p[MAXN],tot;ll phi[MAXN],lmt,n;
    28 const int inv2=500000004;
    29 void mem(int n)
    30 {
    31     phi[1]=1;rep(i,2,n)
    32     {
    33         if(!ntp[i]) p[++tot]=i,phi[i]=i-1;
    34         rep(j,1,tot) if(1LL*i*p[j]>n) break;
    35             else
    36             {
    37                 ntp[i*p[j]]=1;if(i%p[j]) phi[i*p[j]]=mul(phi[i],phi[p[j]]);
    38                 else {phi[i*p[j]]=mul(phi[i],p[j]);break;}
    39             }
    40     }
    41     rep(i,1,n) phi[i]=pls(phi[i-1],phi[i]);
    42 }
    43 map<ll,int> ansp;
    44 ll sum(ll n)
    45 {
    46     n%=MOD;return mul(mul(n,n+1),inv2);
    47 }
    48 ll sphi(ll n,ll res=0)
    49 {
    50     if(n<=lmt) return phi[n];if(ansp[n]) return ansp[n];
    51     for(ll l=2,r;l<=n;l=r+1) r=n/(n/l),res=pls(mul(sphi(n/l),(r-l+1)%MOD),res);
    52     return ansp[n]=mns(sum(n),res);
    53 }
    54 ll solve(ll n,ll res=0)
    55 {
    56     for(ll l=1,r;l<=n;l=r+1)
    57         r=n/(n/l),res=pls(res,mul(mul((n/l)%MOD,(n/l)%MOD),mns(sphi(r),sphi(l-1))));
    58     return res;
    59 }
    60 int main()
    61 {
    62     n=read();mem(lmt=5000000);printf("%lld
    ",solve(n));
    63 }
    View Code

    51nod 1238 最大公倍数之和V3

    题目大意:

    求$sumlimits_{i=1}^n sumlimits_{j=1}^{n} lcm(i,j)$

    思路:

    原式=$sumlimits_ {i=1}^n sumlimits_{j=1}^{n} frac{ij}{gcd(i,j)}$

        $sumlimits_{d=1}^n frac{1}{d}  sumlimits_{i=1}^{n} sumlimits_{j=1}^{n} i cdot j [gcd(i,j)==d]$

          $sumlimits_{d=1}^n d  sumlimits_{i=1}^{n/d} sumlimits_{j=1}^{n/d} i cdot j [gcd(i,j)==1]$

       $sumlimits_{d=1}^n d sumlimits_{g=1}^{n/d} mu(g) sumlimits_{i=1}^{n/d} icdot[g|i] sumlimits_{j=1}^{n/d} j cdot [g|j]$

       $sumlimits_{d=1}^n d  sumlimits_{g=1}^{n/d} mu(g) g^2 sumlimits_{i=1}^{n/gd} i sumlimits_{j=1}^{n/gd} j$

       $sumlimits_{g=1}^n lgroup frac{1}{2} lfloor frac{n}{g} floor cdot lgroup lfloor frac{n}{g} floor +1 group group^2 sumlimits_{d|g} mu(g) g^2 frac{d}{g}$

    记:$f(i)=sumlimits_{d|i} mu(d) d^2 frac{i}{d}$即$f(i)=(mu cdot id^2) * id$ 、记前缀和$S(i)=frac{i(i+1)}{2}$

    原式=$frac{1}{2} sumlimits_{g=1}^{n} S(lfloor frac{n}{g} floor)^2 f(g)       pmb{lbrack1 brack}$

    在这种形式下,只需考虑求$f(i)$前缀和,不妨令$g(i)=id^2$,则有:

    $f*g=((mu cdot id^2)*id)*id^2$

    由于$dirichlet$卷积满足交换律:

    $f*g=((mucdot id^2)*id^2)*id$

    $(f*g)(n)=sumlimits_{g|n} (sumlimits_{d|g} mu(d)cdot d^2cdot frac{g^2}{d^2})cdot frac{n}{g}$

                   $=sumlimits_{g|n} g^2cdot [g=1] cdot frac{n}{g}$

                     $=n sumlimits_{g|n} gcdot [g=1]$

                $=n$

    记$s(n)=sumlimits_{i=1}^n f(i)$

    代入杜教筛公式即有$s(n)=-sumlimits_{i=2}^n g(i) s(n/i) +sumlimits_{i=1}^n i$

    利用平方和公式求$g(i)$的区间和即可用杜教筛求出$f(i)$的前缀和,套用式$ pmb{lbrack 1 brack} $求和即可

    另:

    在线性筛预处理$f(i)$时,化为$f(i)=isumlimits_{d|i}mu(d)d$,由于$mu$的良好性质,最小因子出现多次的情况可以被忽略,容易在线筛过程中推出。

     1 #include<bits/stdc++.h>
     2 #define ll long long
     3 #define MAXN 5001001
     4 #define inf 2139062143
     5 #define MOD 1000000007
     6 #define rep(i,s,t) for(int i=(s),i##end=(t);i<=i##end;++i)
     7 #define dwn(i,s,t) for(int i=(s),i##end=(t);i>=i##end;--i)
     8 #define ren for(int i=fst[x];i;i=nxt[i])
     9 #define pls(a,b) (a+b)%MOD
    10 #define mns(a,b) (a-(b)+MOD)%MOD
    11 #define mul(a,b) (1LL*(a)*(b))%MOD
    12 using namespace std;
    13 int isp[MAXN],p[MAXN],tot;ll f[MAXN],s[MAXN],lmt,n;
    14 const int inv2=500000004,inv6=166666668;
    15 void mem(int n)
    16 {
    17     f[1]=1;rep(i,2,n)
    18     {
    19         if(!isp[i]) p[++tot]=i,f[i]=1-i;
    20         rep(j,1,tot) if(1LL*i*p[j]>n) break;
    21             else {isp[i*p[j]]=1;if(i%p[j]) f[i*p[j]]=f[i]*f[p[j]];else {f[i*p[j]]=f[i];break;}}
    22     }
    23     rep(i,1,n) f[i]=pls(f[i-1],mul(f[i],i));
    24 }
    25 map<ll,int> ansf;
    26 inline ll sum(ll n)
    27 {
    28     n%=MOD;return mul(mul(n,n+1),mul(2*n+1,inv6));
    29 }
    30 inline ll gets(ll n)
    31 {
    32     n%=MOD;return mul(mul(n,n+1),inv2);
    33 }
    34 ll sumf(ll n,ll res=0)
    35 {
    36     if(n<=lmt) return f[n];if(ansf[n]) return ansf[n];
    37     for(ll l=2,r;l<=n;l=r+1) r=n/(n/l),res=pls(res,mul(mns(sum(r),sum(l-1)),sumf(n/l)));
    38     return ansf[n]=mns(gets(n),res);
    39 }
    40 ll solve(ll n,ll res=0)
    41 {
    42     for(ll l=1,r;l<=n;l=r+1)
    43         r=n/(n/l),res=pls(res,mul(mul(gets(n/l),gets(n/l)),mns(sumf(r),sumf(l-1))));
    44     return (res+MOD)%MOD;
    45 }
    46 int main()
    47 {
    48     scanf("%lld",&n);mem(lmt=5000000);printf("%lld
    ",solve(n));
    49 }
    View Code

    51nod 1227 平均最小公倍数

    题目大意:

    令$A(n)=frac{1}{n}sumlimits_{i=1}^n lcm(i,n)$,求$sum_{i=a}^b A(i)$

    思路:

    先化简$A(n)$:

    $A(n)=frac{1}{n}sumlimits_ {i=1}^nfrac{ni}{gcd(n,i)}$

    由于$gcd$为$n$的因数,因此枚举时满足$d|n$

    $A(n)=sumlimits_{d|n} frac{1}{d} sumlimits_{i=1}^{n} i [gcd(i,n)==d]$

      ​   $sumlimits_{d|n}sumlimits_{i=1}^{n/d} i [gcd(i,frac{n}{d})==1]$

    ​     $sumlimits_{d|n} sumlimits_{i=1}^{n/d}isumlimits_{g|gcd(i,n/d)} mu(g)$

        ​ $sumlimits_{d|n}sumlimits_{g|frac{n}{d}} mu(g) sumlimits_{i=1}^{n/g}icdot lbrack g|i brack $

      ​   $sumlimits_{d|n}sumlimits_{g|frac{n}{d}} mu(g)g sumlimits_{i=1}^{n/gd}i$

      ​   $sumlimits_{g|n} frac{frac{n}{g} cdot lgroup frac{n}{g}+1 group}{2}sumlimits_{d|g} mu(d)d$$

    令$h(n)=sumlimits_{d|n} mu(d)d$即$h(n)=(mu cdot id)*1$

    即$A(n)=frac{1}{2} (sumlimits_{g|n} frac{n}{g} cdot h(g)+sumlimits_{g|n} (frac{n}{g})^2 cdot h(g))$

    要求$A(n)$的前缀和,将这两项分开考虑:

    前半部分$=id*((mucdot id)*1)=(mu cdot id )*id*1=[n=1]*1=1$,计算非常简单

    后半部分$id^2 *(mu cdot id)*1$,设为$f(i)$,考虑取$g(i)=id$,则有:

    $f*g=(mucdot id)*id*1*id^2=1* id^2$

    $sumlimits_{i=1}^n (f*g)(n)=sumlimits_{i=1}^nsumlimits_{d|i}d^2$

    ​         $=sumlimits_{d=1}^n d^2sumlimits_{i=1}^n [d|i]$

    ​         $=sumlimits_{d=1}^n d^2 cdot lfloor frac{n}{d} floor$

    则该卷积结果的前缀和可以通过数论分块求出,在杜教筛求后半部分的同时顺便求出即可

    将两部分的和相加后乘$2$的逆元即可

    另:

    在线性筛处理$f(i)$时,将$f(i)$化为$(varphicdot id)*1$,在过程中处理出最小因子最高次幂的贡献,可以顺利处理出每个质因子次数$ge2$的情况。

     1 #include<bits/stdc++.h>
     2 #define inf 2139062143
     3 #define MAXN 5001001
     4 #define MOD 1000000007
     5 #define ll long long
     6 #define ull unsigned long long
     7 #define rep(i,s,t) for(register int i=(s),i##end=(t);i<=i##end;++i)
     8 #define dwn(i,s,t) for(register int i=(s),i##end=(t);i>=i##end;--i)
     9 #define ren for(register int i=fst[x];i;i=nxt[i])
    10 #define Fill(a,b) memset(a,b,sizeof(a))
    11 #define pls(a,b) (a+b)%MOD
    12 #define mns(a,b) (a-(b)+MOD)%MOD
    13 #define mul(a,b) (1LL*(a)*(b)%MOD)
    14 #define pii pair<int,int>
    15 #define mp(a,b) make_pair(a,b)
    16 #define pb(i,x) vec[i].push_back(x)
    17 #define fi first
    18 #define se second
    19 using namespace std;
    20 inline ll read()
    21 {
    22     ll x=0;bool f=1;char ch=getchar();
    23     while(!isdigit(ch)) {if(ch=='-') f=0;ch=getchar();}
    24     while(isdigit(ch)) x=x*10+(ch^48),ch=getchar();
    25     return f?x:-x;
    26 }
    27 int ntp[MAXN],p[MAXN],tot;ll f[MAXN],lmt,n,m,g[MAXN];
    28 const int inv2=500000004,inv6=166666668;
    29 int gcd(int a,int b){return !b?a:gcd(b,a%b);}
    30 void mem(int n)
    31 {
    32     f[1]=1;rep(i,2,n)
    33     {
    34         if(!ntp[i]) p[++tot]=i,f[i]=mns(mul(i,i),i-1),g[i]=mns(f[i],1);
    35         rep(j,1,tot) if(1LL*i*p[j]>n) break;
    36             else
    37             {
    38                 ntp[i*p[j]]=1;if(i%p[j]) f[i*p[j]]=mul(f[i],f[p[j]]),g[i*p[j]]=mns(f[i*p[j]],f[i]);
    39                 else {g[i*p[j]]=mul(g[i],mul(p[j],p[j])),f[i*p[j]]=pls(g[i*p[j]],f[i]);break;}
    40             }
    41     }
    42     rep(i,1,n) f[i]=pls(f[i-1],f[i]);
    43 }
    44 map<ll,int> ansf;
    45 ll gets(ll n,ll res=0)
    46 {
    47     n%=MOD;return mul(mul(n,n+1),mul(2*n+1,inv6));
    48 }
    49 ll solve(ll n,ll sum=0,ll res=0)
    50 {
    51     if(n<=lmt) return f[n];if(ansf[n]) return ansf[n];
    52     sum=n%MOD;for(ll l=2,r;l<=n;l=r+1) 
    53         r=n/(n/l),res=pls(mul(mul(solve(n/l),inv2),mul(r-l+1,(r+l)%MOD)),res),
    54         sum=pls(sum,mul((n/l)%MOD,mns(gets(r),gets(l-1))));
    55     return ansf[n]=mns(sum,res);
    56 }
    57 int main()
    58 {
    59     m=read(),n=read();mem(lmt=5000000);
    60     printf("%lld
    ",mul(pls(mns(solve(n),solve(m-1)),mns(n+1,m)),inv2));
    61 }
    View Code

    51nod 1222 最小公倍数计数

    题目大意:

    定义$F(i)$表示最小公倍数为$n$的二元组$(x,y)$其中$xle y$的数量,求$sumlimits_{i=a}^b F(i)$

    思路:

    题目所求显然可以通过计算不考虑$x$与$y$的大小关系的情况下的答案快速得出,即加上$x=y$的情况再除以二即可。

    只需计算$F(i)$的前缀和,即:

    $sumlimits_{i=1}^n F(i)=sumlimits_{i=1}^n sumlimits_{j=1}^n [lcm(i,j)le n]$

    ​      $=sumlimits_{d=1}^nsumlimits_{i=1}^nsumlimits_{j=1}^n [frac{ij}{d}le n][gcd(i,j)=d]$

          $=sumlimits_{d=1}^n sumlimits_{i=1}^{n/d}sumlimits_{j=1}^{n/d} [ijdle n][gcd(i,j)=1]$

          $=sumlimits_{d=1}^n sumlimits_{k=1}^{n/d}mu(k)sumlimits_{i=1}^{n/dk}sumlimits_{j=1}^{n/dk} [ijdle lfloor frac{n}{k^2} floor]$

    考虑先枚举$k$,由于后续需要计算$ijdle lfloor frac{n}{k^2} floor $,故$k$只需枚举到$sqrt n$即可,后续枚举时上界也同样可以缩小,即:

    $sumlimits_{i=1}^nF(i)=sumlimits_{k=1}^{sqrt n} mu(k) sumlimits_{d=1}^{lfloor frac{n}{k^2} floor }sumlimits_{i=1}^{lfloorfrac{n}{dk^2} floor} sumlimits_{j=1}^{lfloor frac{n}{idk^2} floor} [ijdle lfloor frac{n}{k^2} floor]$

    令$g(n)=sumlimits_{d=1}^nsumlimits_{i=1}^{lfloorfrac{n}{d} floor} sumlimits_{j=1}^{lfloor frac{n}{id} floor} [ijdle n]$,在枚举时不妨令$dle ile j$,则在枚举$dle sqrt[3]n,ile sqrt{frac{n}{i} }$之后可以直接计算出符合条件的$j$的数量,再特判相等时候的贡献即可。

     1 #include<bits/stdc++.h>
     2 #define inf 2139062143
     3 #define MAXN 500100
     4 #define MOD 1000000007
     5 #define ll long long
     6 #define ull unsigned long long
     7 #define rep(i,s,t) for(register int i=(s),i##end=(t);i<=i##end;++i)
     8 #define dwn(i,s,t) for(register int i=(s),i##end=(t);i>=i##end;--i)
     9 #define ren for(register int i=fst[x];i;i=nxt[i])
    10 #define Fill(a,b) memset(a,b,sizeof(a))
    11 #define pls(a,b) (a+b)%MOD
    12 #define mns(a,b) (a-(b)+MOD)%MOD
    13 #define mul(a,b) (1LL*(a)*(b)%MOD)
    14 #define pii pair<int,int>
    15 #define mp(a,b) make_pair(a,b)
    16 #define pb(i,x) vec[i].push_back(x)
    17 #define fi first
    18 #define se second
    19 using namespace std;
    20 inline ll read()
    21 {
    22     ll x=0;bool f=1;char ch=getchar();
    23     while(!isdigit(ch)) {if(ch=='-') f=0;ch=getchar();}
    24     while(isdigit(ch)) x=x*10+(ch^48),ch=getchar();
    25     return f?x:-x;
    26 }
    27 ll a,b;
    28 int mu[MAXN],p[MAXN],tot,isp[MAXN];
    29 void mem(int n)
    30 {
    31     mu[1]=1;rep(i,2,n)
    32     {
    33         if(!isp[i]) p[++tot]=i,mu[i]=-1;
    34         rep(j,1,tot) if(i*p[j]>n) break;
    35             else {isp[i*p[j]]=1;if(i%p[j]) mu[i*p[j]]=-mu[i];else break;}
    36     }
    37 }
    38 ll calc(ll n,ll res=0)
    39 {
    40     ll t;for(ll i=1;i*i*i<=n;++i)
    41         for(ll j=i;i*j*j<=n;++j)
    42         {
    43             t=n/i/j;if(t<j) break;t-=j-1;
    44             if(i==j) res+=t*3-2;else res+=t*6-3;
    45         }
    46     return res;
    47 }
    48 ll solve(ll n,ll res=0)
    49 {
    50     rep(i,1,sqrt(n)) res+=mu[i]*calc(n/i/i);return (res+n)>>1;
    51 }
    52 int main()
    53 {
    54     a=read(),b=read();mem(500000);
    55     printf("%lld
    ",solve(b)-solve(a-1));
    56 }
    View Code

    bzoj 4176 Lucas的数论

    题目大意:

    求$sumlimits_{i=1}^n sumlimits_{j=1}^n d(ij)$,其中$d(n)$表示$n$的约数个数

    思路:

    首先有结论$d(nm)=sumlimits_{i|n}sumlimits_{j|m} [gcd(i,j)=1]$,简略证明:

    设$n=prodlimits_{i=1} p_i^{alpha_i}$,$m=prodlimits_{j=1}p_j^{eta_j}$

    考虑对每个质因数$p$,符合条件的$i$,$j$一定只能有一个含有因子$p$

    两种情况分别有$eta$与$alpha$ ,一共$alpha + eta$恰好表示$p$对于$nm$的贡献

    代入得:

    原式 $=sumlimits_{i=1}^n sumlimits_{j=1}^n sumlimits_{p|i}sumlimits_{q|j} [gcd(p,q)==1]$

    ​   $=sumlimits_{i=1}^n sumlimits_{j=1}^n sumlimits_{p|i}sumlimits_{q|j}sumlimits_{d=1}^n mu(d) [d|p][d|q]$

    ​   $=sumlimits_{d=1}^n mu(d)sumlimits_{p=1}^{n/d} sumlimits_{q=1}^{n/d} sumlimits_{i=1}^{n/pd}sumlimits_{j=1}^{n/qd} 1$

    ​   $=sumlimits_{d=1}^n mu(d) lgroup sumlimits_{p=1}^{n/d} lfloor frac{n}{pd} floor group lgroup sumlimits_{q=1}^{n/d} lfloor frac{n}{qd} floor group $

    ​   $=sumlimits_{d=1}^n mu(d) lgroup sumlimits_{i=1}^{n/d} lfloor frac{n}{id} floor group^2 $

    令$f(n)=sumlimits_{i=1}^n lfloor frac{n}{i} floor $,即原式$=sumlimits_{d=1}^n mu(d) f(lfloor frac{n}{d} floor)^2 $

    $f(i)$可以通过分块快速计算,只需预处理$mu$的前缀和即可

     1 #include<bits/stdc++.h>
     2 #define inf 2139062143
     3 #define MAXN 5001001
     4 #define MOD 1000000007
     5 #define ll long long
     6 #define ull unsigned long long
     7 #define rep(i,s,t) for(register int i=(s),i##end=(t);i<=i##end;++i)
     8 #define dwn(i,s,t) for(register int i=(s),i##end=(t);i>=i##end;--i)
     9 #define ren for(register int i=fst[x];i;i=nxt[i])
    10 #define Fill(a,b) memset(a,b,sizeof(a))
    11 #define pls(a,b) (a+b)%MOD
    12 #define mns(a,b) (a-(b))%MOD
    13 #define mul(a,b) (1LL*(a)*(b)%MOD)
    14 #define pii pair<int,int>
    15 #define mp(a,b) make_pair(a,b)
    16 #define pb(i,x) vec[i].push_back(x)
    17 #define fi first
    18 #define se second
    19 using namespace std;
    20 inline int read()
    21 {
    22     int x=0;bool f=1;char ch=getchar();
    23     while(!isdigit(ch)) {if(ch=='-') f=0;ch=getchar();}
    24     while(isdigit(ch)) x=x*10+(ch^48),ch=getchar();
    25     return f?x:-x;
    26 }
    27 int n,lmt,mu[MAXN],p[MAXN],tot,isp[MAXN];
    28 void mem(int n)
    29 {
    30     mu[1]=1;rep(i,2,n)
    31     {
    32         if(!isp[i]) p[++tot]=i,mu[i]=-1;
    33         rep(j,1,tot) if(i*p[j]>=n) break;
    34             else {isp[i*p[j]]=1;if(i%p[j]) mu[i*p[j]]=-mu[i];else break;}
    35     }
    36     rep(i,1,n) mu[i]=pls(mu[i-1],mu[i]);
    37 }
    38 map<int,int> ansm;
    39 int smu(int n,int res=0)
    40 {
    41     if(n<=lmt) return mu[n];if(ansm[n]) return ansm[n];
    42     for(int l=2,r;l<=n;l=r+1) r=n/(n/l),res=pls(mul(r-l+1,smu(n/l)),res);
    43     return ansm[n]=mns(1,res);
    44 }
    45 int calc(int n,int res=0)
    46 {
    47     for(int l=1,r;l<=n;l=r+1) r=n/(n/l),res=pls(res,mul(r-l+1,(n/l)%MOD));
    48     return mul(res,res);
    49 }
    50 int solve(int n,int res=0)
    51 {
    52     for(int l=1,r;l<=n;l=r+1)
    53         r=n/(n/l),res=pls(mul(mns(smu(r),smu(l-1)),calc(n/l)),res);
    54     return (res+MOD)%MOD;
    55 }
    56 int main()
    57 {
    58     n=read();mem(lmt=5000000);printf("%d
    ",solve(n));
    59 }
    View Code

    51nod 1220 约数之和

    题目大意:

    求$sumlimits_{i=1}^n sumlimits_{j=1}^n sigma(ij)$,其中$sigma(n)$表示$n$的约数和

    思路:

    首先有结论$sigma(nm)=sumlimits_{i|n}sumlimits_{j|m} frac{im}{j}cdot [gcd(i,j)=1]$,证明与上题类似:

    设$n=prodlimits_{i=1} p_i^{alpha_i}$,$m=prodlimits_{j=1}p_j^{eta_j}$

    考虑对每个质因数$p$,符合条件的$i$,$j$一定只能有一个含有因子$p$

    两种情况分别对应$1 p^1cdots p^{eta}$与$p^{eta}cdots p^{alpha+eta}$ ,一共恰好表示$p$对于$nm$的贡献

    将这个式子代入:

    原式 $=sumlimits_{i=1}^n sumlimits_{j=1}^n sumlimits_{p|i}sumlimits_{q|j} frac{pj}{q} cdot [gcd(p,q)==1]$

    ​   $=sumlimits_{i=1}^n sumlimits_{j=1}^n sumlimits_{p|i}sumlimits_{q|j}sumlimits_{d=1}^n mu(d) frac{pj}{q}[d|p][d|q]$

    ​   $=sumlimits_{d=1}^n mu(d)sumlimits_{p=1}^{n/d} sumlimits_{q=1}^{n/d} sumlimits_{i=1}^{n/pd}sumlimits_{j=1}^{n/qd} pd cdot j$

      ​ $=sumlimits_{d=1}^n mu(d)d lgroup sumlimits_{p=1}^{n/d} p lfloor frac{n}{pd} floor group lgroup sumlimits_{q=1}^{n/d} sumlimits_{j=1}^{n/qd} j group$

    设中间两部分分别为$f(lfloorfrac{n}{d} floor)$与$g(lfloorfrac{n}{d} floor)$,其中$f(n)=sumlimits_{i=1}^n ilfloorfrac{n}{i} floor$,$g(n)=sumlimits_{i=1}^nsumlimits_{j=1}^{lfloorfrac{n}{i} floor}j$

    考虑$f(n)$的实际意义,即每个$i$乘以它在$le n$范围内倍数个数,故$f(n)=sumlimits_{i=1}^n sigma_1(i)$

    又$g(n)=sumlimits_{j=1}^{n}jsumlimits_{i=1}^{lfloorfrac{n}{j} floor}1=sumlimits_{j=1}^n j lfloorfrac{n}{j} floor=f(n)$

    代入原式$=sumlimits_{d=1}^n mu(d)d lgroup sumlimits_{i=1}^{lfloorfrac{n}{d} floor}sigma_1(i) group^2$

    对于$mu cdot id$的前缀和,与之前题目做法一样,卷上$id$即可解决,

    对$f(n/d)$的计算,较小的情况可以用线性筛预处理,记录一下最小质因子的贡献即可;较大的情况直接采用$f(n)$的式子计算即可,复杂度分析与杜教筛类似。

     1 #include<bits/stdc++.h>
     2 #define inf 2139062143
     3 #define MAXN 5001001
     4 #define MOD 1000000007
     5 #define ll long long
     6 #define ull unsigned long long
     7 #define rep(i,s,t) for(register int i=(s),i##end=(t);i<=i##end;++i)
     8 #define dwn(i,s,t) for(register int i=(s),i##end=(t);i>=i##end;--i)
     9 #define ren for(register int i=fst[x];i;i=nxt[i])
    10 #define Fill(a,b) memset(a,b,sizeof(a))
    11 #define pls(a,b) (a+b)%MOD
    12 #define mns(a,b) (a-(b))%MOD
    13 #define mul(a,b) (1LL*(a)*(b)%MOD)
    14 #define pii pair<int,int>
    15 #define mp(a,b) make_pair(a,b)
    16 #define pb(i,x) vec[i].push_back(x)
    17 #define fi first
    18 #define se second
    19 using namespace std;
    20 inline int read()
    21 {
    22     int x=0;bool f=1;char ch=getchar();
    23     while(!isdigit(ch)) {if(ch=='-') f=0;ch=getchar();}
    24     while(isdigit(ch)) x=x*10+(ch^48),ch=getchar();
    25     return f?x:-x;
    26 }
    27 int n,lmt;
    28 int mu[MAXN],f[MAXN],g[MAXN],p[MAXN],tot,isp[MAXN];
    29 void mem(int n)
    30 {
    31     mu[1]=f[1]=g[1]=1;rep(i,2,n)
    32     {
    33         if(!isp[i]) p[++tot]=i,mu[i]=-1,f[i]=1,g[i]=1+i;
    34         rep(j,1,tot) if(i*p[j]>n) break;
    35             else
    36             {
    37                 isp[i*p[j]]=1;
    38                 if(i%p[j]) mu[i*p[j]]=-mu[i],f[i*p[j]]=mul(f[i],g[i]),g[i*p[j]]=p[j]+1;
    39                 else {f[i*p[j]]=f[i],g[i*p[j]]=pls(mul(g[i],p[j]),1);break;}
    40             }
    41     }
    42     rep(i,1,n) mu[i]=pls(mu[i-1],mul(mu[i],i));
    43     rep(i,1,n) f[i]=pls(f[i-1],mul(f[i],g[i]));
    44 }
    45 map<int,int> ansm;
    46 int sum(int l,int r) {return (1LL*(r-l+1)*(r+l)>>1LL)%MOD;}
    47 int smu(int n,int res=0)
    48 {
    49     if(n<=lmt) return mu[n];if(ansm[n]) return ansm[n];
    50     for(int l=2,r;l<=n;l=r+1) r=n/(n/l),res=pls(mul(sum(l,r),smu(n/l)),res);
    51     return ansm[n]=mns(1,res); 
    52 }
    53 int calc(int n,int res=0)
    54 {
    55     if(n<=lmt) return mul(f[n],f[n]);
    56     for(int l=1,r;l<=n;l=r+1) r=n/(n/l),res=pls(res,mul(sum(l,r),n/l));
    57     return mul(res,res);
    58 }
    59 int solve(int n,int res=0)
    60 {
    61     for(int l=1,r;l<=n;l=r+1)
    62         r=n/(n/l),res=pls(mul(mns(smu(r),smu(l-1)),calc(n/l)),res);
    63     return (res+MOD)%MOD;
    64 }
    65 int main()
    66 {
    67     n=read();mem(lmt=5000000);printf("%d
    ",solve(n));
    68 }
    View Code

    51nod 1584 加权约数和

    题目大意:

    $sumlimits_{i=1}^n sumlimits_{j=1}^n max(i,j)cdot sigma(ij)$

    思路:

    先将$max(i,j)$转化为另一个形式$sumlimits_{k=1}^n [kle i or kge j]$,即$n-sumlimits_{k=1}^n[k>i][k>j]$

    将式子代入:

    原式$=sumlimits_{i=1}^nsumlimits_{j=1}^n (n-sumlimits_{k=1}^n [k>i][k>j])cdot sigma(ij)$

    ​  $=ncdot sumlimits_{i=1}^nsumlimits_{j=1}^nsigma(ij)-sumlimits_{k=1}^nsumlimits_{i=1}^{k-1}sumlimits_{j=1}^{k-1}sigma(ij)$

    令$f(n)=sumlimits_{i=1}^nsumlimits_{j=1}^nsigma(ij)$,则原式$=ncdot f(n)-sumlimits_{k=1}^{n-1} f(k)$

    发现$f(n)$就是上一题的式子

    $f(n)=sumlimits_{d=1}^n mu(d)d lgroup sumlimits_{i=1}^{lfloorfrac{n}{d} floor}sigma(i) group^2$

    由于本题需要计算$f(n)$的前缀和,使用杜教筛复杂度$O(nsqrt n)$过高

    因为$nle 10^6$且有多组数据,考虑使用$nlogn$预处理$f(n)$,以便快速查询

    在线性筛出$mu$与$sumlimits_{i=1}^nsigma(i)$之后,枚举$d$与$n/d$之后对一段连续的$n$的贡献相同,因此可以快速得到$f(n)$的差分数组

    然后求两次前缀和即可得到$f(n)$的前缀和数组

     1 #include<bits/stdc++.h>
     2 #define inf 2139062143
     3 #define MAXN 1001001
     4 #define MOD 1000000007
     5 #define ll long long
     6 #define ull unsigned long long
     7 #define rep(i,s,t) for(register int i=(s),i##end=(t);i<=i##end;++i)
     8 #define dwn(i,s,t) for(register int i=(s),i##end=(t);i>=i##end;--i)
     9 #define ren for(register int i=fst[x];i;i=nxt[i])
    10 #define Fill(a,b) memset(a,b,sizeof(a))
    11 #define pls(a,b) (a+b)%MOD
    12 #define mns(a,b) (a-(b))%MOD
    13 #define mul(a,b) (1LL*(a)*(b)%MOD)
    14 #define pii pair<int,int>
    15 #define mp(a,b) make_pair(a,b)
    16 #define pb(i,x) vec[i].push_back(x)
    17 #define fi first
    18 #define se second
    19 using namespace std;
    20 inline int read()
    21 {
    22     int x=0;bool f=1;char ch=getchar();
    23     while(!isdigit(ch)) {if(ch=='-') f=0;ch=getchar();}
    24     while(isdigit(ch)) x=x*10+(ch^48),ch=getchar();
    25     return f?x:-x;
    26 }
    27 int n,lmt;
    28 int mu[MAXN],f[MAXN],g[MAXN],p[MAXN],tot,isp[MAXN],ans[MAXN<<1];
    29 void mem(int n)
    30 {
    31     mu[1]=f[1]=g[1]=1;rep(i,2,n)
    32     {
    33         if(!isp[i]) p[++tot]=i,mu[i]=-1,f[i]=1,g[i]=1+i;
    34         rep(j,1,tot) if(i*p[j]>n) break;
    35             else
    36             {
    37                 isp[i*p[j]]=1;
    38                 if(i%p[j]) mu[i*p[j]]=-mu[i],f[i*p[j]]=mul(f[i],g[i]),g[i*p[j]]=p[j]+1;
    39                 else {f[i*p[j]]=f[i],g[i*p[j]]=pls(mul(g[i],p[j]),1);break;}
    40             }
    41     }
    42     rep(i,1,n) mu[i]=mul(mu[i],i),f[i]=pls(mul(f[i],g[i]),f[i-1]);
    43     rep(i,1,n) f[i]=mul(f[i],f[i]);
    44 }
    45 inline int calc(int n){return mns(mul(n,ans[n]),mul(n+1,ans[n-1]));}
    46 int main()
    47 {
    48     mem(lmt=1000000);
    49     rep(i,1,lmt) rep(j,1,lmt/i)
    50         ans[i*j]=pls(ans[i*j],mul(mu[i],f[j])),ans[i*j+i]=mns(ans[i*j+i],mul(mu[i],f[j]));
    51     rep(i,1,lmt) ans[i]=pls(ans[i-1],ans[i]);
    52     rep(i,1,lmt) ans[i]=pls(ans[i-1],ans[i]);
    53     for(int T=read(),t=1;t<=T;++t)
    54         n=read(),printf("Case #%d: %d
    ",t,(calc(n)+MOD)%MOD);
    55 }
    View Code
  • 相关阅读:
    java8
    java7
    java6
    java5
    java复习4
    学习笔记
    Reflection笔记
    通过Reflection来获得方法和信息
    學習反射2
    學習反射1
  • 原文地址:https://www.cnblogs.com/yyc-jack-0920/p/14407368.html
Copyright © 2020-2023  润新知