@xiaoziyao
        
        2021-05-02T01:02:43.000000Z
        字数 10988
        阅读 1868
    数学 学习笔记
upd:内容比较老旧,但是不想更新了,到时候会写在另一个博客里。
主要是上一篇字数太多,太卡了,于是杜教筛就换了一篇写 多水了一篇博客
先讲一下前置知识:
莫比乌斯函数,即
狄利克雷卷积,可以表示为
狄利克雷卷积满足交换律和结合律,且存在单位元
简证为单位元:
例子:
重要的数论函数中互相转化: 
在莫比乌斯反演的应用题中,经常会有的形式,但是的复杂度有时候仍然满足不了需求
为了解决这一问题,我们就要用到整除分块
很容易发现很多的值是一样的,且所有的为一个不下降子序列,呈块状分布
通过简单的计算可以得到,对于每个起点为的块,它的值为,终点为,然后我们就可以用的算法计算的值了
代码:
int l=1,r,ans=0;if(n>m)swp(n,m);while(l<=n){r=min(n/(n/l),mm/(m/l));ans+=(r-l+1)*(n/l);l=r+1;}
我们要筛一个积性函数的前缀和,杜教筛可以帮我们做到(当然可以记忆化常数优化)
我们设,其中为积性函数
我们找一个可以与卷积的积性函数,推一下它们的狄利克雷卷积前缀和:
我们可以递归求解,而且可以设一个边界,如果则直接输出预处理的前缀和
然后我们考虑的值: 
此时,如果找到一个合适的使与的前缀和可以很容易处理,那么就可以用数论分块递归求解
我们可以由这个表得出一些数论函数相应的函数:
即:
1.例题1:P4213 【模板】杜教筛(Sum) 
题意:共组数据,每组数据给定,求和
我们根据上面的表很容易写出来,因此没有什么推导过程
代码:
#include<stdio.h>#include<map>using namespace std;const long long maxn=3000005;long long i,j,k,m,n,T,cnt;long long a[maxn],p[maxn],varphi[maxn],mu[maxn],sumvarphi[maxn],summu[maxn];map<long long,long long>ansvarphi,ansmu;long long getvarphi(long long n){if(n<maxn)return sumvarphi[n];if(ansvarphi.count(n))return ansvarphi[n];long long l=2,r,res=n*(n+1)/2;while(l<=n){r=n/(n/l);res-=(r-l+1)*getvarphi(n/l);l=r+1;}return ansvarphi[n]=res;}long long getmu(long long n){if(n<maxn)return summu[n];if(ansmu.count(n))return ansmu[n];long long l=2,r,res=1;while(l<=n){r=n/(n/l);res-=(r-l+1)*getmu(n/l);l=r+1;}return ansmu[n]=res;}int main(){p[1]=varphi[1]=mu[1]=1;for(i=2;i<maxn;i++){if(p[i]==0)a[++cnt]=i,varphi[i]=i-1,mu[i]=-1;for(j=1;j<=cnt;j++){if(i*a[j]>=maxn)break;p[i*a[j]]=1;if(i%a[j]==0){varphi[i*a[j]]=varphi[i]*a[j],mu[i*a[j]]=0;break;}varphi[i*a[j]]=varphi[i]*(a[j]-1),mu[i*a[j]]=-mu[i];}}for(i=1;i<maxn;i++)sumvarphi[i]=sumvarphi[i-1]+varphi[i],summu[i]=summu[i-1]+mu[i];scanf("%lld",&T);while(T--){scanf("%lld",&n);printf("%lld %lld\n",getvarphi(n),getmu(n));}return 0;}
2.例题2:简单的数学题 
题意:求 
数据范围: 
相信大家都看了之前莫比乌斯反演的讲解,因此这里过程简单一点: 
代码:
#include<stdio.h>#include<map>using namespace std;const long long maxn=5000005;long long i,j,k,m,n,mod,cnt,inv6;long long a[maxn],p[maxn],varphi[maxn],S[maxn];map<long long,long long>ans;inline long long getsum(long long n){return n*(n+1)/2%mod;}inline long long calc(long long n){return n*(n+1)%mod*(2*n+1)%mod*inv6%mod;}long long ksm(long long a,long long b,long long mod){long long res=1;while(b){if(b&1)res=(res*a)%mod;a=(a*a)%mod,b>>=1;}return res;}long long getS(long long n){if(n<maxn)return S[n];if(ans.count(n))return ans[n];long long l=2,r,res=getsum(n)*getsum(n)%mod;while(l<=n){r=n/(n/l);res=((res-(calc(r)-calc(l-1)+mod)%mod*getS(n/l)%mod)%mod+mod)%mod;l=r+1;}res=(res%mod+mod)%mod;return ans[n]=res;}long long getans(long long n){long long l=1,r,res=0;while(l<=n){r=n/(n/l);res=(res+(getS(r)-getS(l-1)+mod)%mod*getsum(n/l)%mod*getsum(n/l)%mod)%mod;l=r+1;}res=(res%mod+mod)%mod;return res;}int main(){scanf("%lld%lld",&mod,&n);inv6=ksm(6,mod-2,mod);p[1]=varphi[1]=1;for(i=2;i<maxn;i++){if(p[i]==0)a[++cnt]=i,varphi[i]=i-1;for(j=1;j<=cnt;j++){if(i*a[j]>=maxn)break;p[i*a[j]]=1;if(i%a[j]==0){varphi[i*a[j]]=varphi[i]*a[j];break;}varphi[i*a[j]]=varphi[i]*(a[j]-1);}}for(i=1;i<maxn;i++)S[i]=(S[i-1]+varphi[i]%mod*i%mod*i%mod)%mod;printf("%lld\n",getans(n));return 0;}