@xiaoziyao
2020-10-18T07:36:37.000000Z
字数 27560
阅读 2737
数学 学习笔记
莫比乌斯函数,即
狄利克雷卷积,可以表示为
狄利克雷卷积满足交换律和结合律,且存在单位元
简证为单位元:
例子:
重要的数论函数中互相转化:
在莫比乌斯反演的应用题中,经常会有的形式,但是的复杂度有时候仍然满足不了需求
为了解决这一问题,我们就要用到整除分块
很容易发现很多的值是一样的,且所有的为一个不下降子序列,呈块状分布
通过简单的计算可以得到,对于每个起点为的块,它的值为,终点为,然后我们就可以用的算法计算的值了
代码:
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.求值:
#include<stdio.h>const int maxn=100005;int i,j,k,m,n,T,cnt,l,r,ans;int a[maxn],p[maxn],mu[maxn],sum[maxn];inline void swp(int &a,int &b){a+=b,b=a-b,a-=b;}inline int min(int a,int b){return a<b? a:b;}int main(){p[1]=mu[1]=1;for(i=2;i<maxn;i++){if(p[i]==0)a[++cnt]=i,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)mu[i*a[j]]=0;else mu[i*a[j]]=-mu[i];}}for(i=1;i<maxn;i++)sum[i]=sum[i-1]+mu[i];scanf("%d",&T);while(T--){scanf("%d%d%d",&n,&m,&k);n/=k,m/=k;if(n>m)swp(n,m);l=1,ans=0;while(l<=n){r=min(n/(n/l),m/(m/l));ans+=(sum[r]-sum[l-1])*(n/l)*(m/l);l=r+1;}printf("%d\n",ans);}return 0;}
3.例题2:[HAOI2011]Problem b
题意:共组数据,求值
数据范围:
这道题与例题1很像,但是和不是从开始的,因此这有点像在一个二维平面内取一个矩形,你想到了什么?容斥定理!
我们只需要写一个跟例题1一样的函数求值
二维容斥:
#include<stdio.h>const int maxn=100005;int i,j,k,m,n,a,b,c,d,T,cnt;int z[maxn],p[maxn],mu[maxn],sum[maxn];inline void swp(int &a,int &b){a+=b,b=a-b,a-=b;}inline int min(int a,int b){return a<b? a:b;}int calc(int n,int m,int k){int l=1,r,res=0;n/=k,m/=k;if(n>m)swp(n,m);while(l<=n){r=min(n/(n/l),m/(m/l));res+=(sum[r]-sum[l-1])*(n/l)*(m/l);l=r+1;}return res;}int main(){p[1]=mu[1]=1;for(i=2;i<maxn;i++){if(p[i]==0)z[++cnt]=i,mu[i]=-1;for(j=1;j<=cnt;j++){if(i*z[j]>=maxn)break;p[i*z[j]]=1;if(i%z[j]==0)mu[i*z[j]]=0;else mu[i*z[j]]=-mu[i];}}for(i=1;i<maxn;i++)sum[i]=sum[i-1]+mu[i];scanf("%d",&n);for(i=1;i<=n;i++){scanf("%d%d%d%d%d",&a,&b,&c,&d,&k);printf("%d\n",calc(b,d,k)-calc(b,c-1,k)-calc(a-1,d,k)+calc(a-1,c-1,k));}return 0;}
4.例题3:YY的GCD
题意:共组数据,求
数据范围:
不妨设,很自然可以想到枚举质数的套路:
#include<stdio.h>const int maxn=10000005;int i,j,k,m,n,cnt,T,l,r;long long ans;int a[maxn],p[maxn],mu[maxn],f[maxn],sum[maxn];inline void swp(int &a,int &b){a+=b,b=a-b,a-=b;}inline int min(int a,int b){return a<b? a:b;}int main(){p[1]=mu[1]=1;for(i=2;i<maxn;i++){if(p[i]==0)a[++cnt]=i,mu[i]=-1,f[i]=1;for(j=1;j<=cnt;j++){if(i*a[j]>maxn)break;p[i*a[j]]=1;if(i%a[j]==0){mu[i*a[j]]=0;f[i*a[j]]=mu[i];break;}mu[i*a[j]]=-mu[i];f[i*a[j]]=mu[i]-f[i];}sum[i]=sum[i-1]+f[i];}scanf("%d",&T);while(T--){scanf("%d%d",&n,&m);if(n>m)swp(n,m);l=1,ans=0;while(l<=n){r=min(n/(n/l),m/(m/l));ans+=(long long)(n/l)*(long long)(m/l)*(long long)(sum[r]-sum[l-1]);l=r+1;}printf("%lld\n",ans);}return 0;}
5.求值
#include<stdio.h>const int maxn=50005;int i,j,k,m,n,T,cnt,l,r;long long ans;int a[maxn],p[maxn],mu[maxn],sum[maxn];long long f[maxn];inline void swp(int &a,int &b){a+=b,b=a-b,a-=b;}inline int min(int a,int b){return a<b? a:b;}int main(){p[1]=mu[1]=1;for(i=2;i<maxn;i++){if(p[i]==0)a[++cnt]=i,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){mu[i*a[j]]=0;break;}mu[i*a[j]]=-mu[i];}}for(i=1;i<maxn;i++)sum[i]=sum[i-1]+mu[i];for(i=1;i<maxn;i++){l=1,ans=0;while(l<=i){r=i/(i/l);ans+=(r-l+1)*(i/l);l=r+1;}f[i]=ans;}scanf("%d",&T);while(T--){scanf("%d%d",&n,&m);if(n>m)swp(n,m);l=1,ans=0;while(l<=n){r=min(n/(n/l),m/(m/l));ans+=(long long)(sum[r]-sum[l-1])*(long long)f[n/l]*(long long)f[m/l];l=r+1;}printf("%lld\n",ans);}return 0;}
7.例题5:[国家集训队]Crash的数字表格 / JZPTAB
题意:求
数据范围:
由
#include<stdio.h>const int maxn=10000005;const long long mod=20101009;long long i,j,k,m,n,cnt,l,r,ans;long long a[maxn],p[maxn],mu[maxn],sum[maxn];inline void swp(long long &a,long long &b){a+=b,b=a-b,a-=b;}inline long long min(long long a,long long b){return a<b? a:b;}inline long long calc(long long x,long long y){return (x*(x+1)/2%mod)*(y*(y+1)/2%mod)%mod;}long long f(long long n,long long m){if(n>m)swp(n,m);long long l=1,r,res=0;while(l<=n){r=min(n/(n/l),m/(m/l));res=(res+(sum[r]-sum[l-1]+mod)%mod*calc(n/l,m/l))%mod;l=r+1;}return res;}int main(){p[1]=mu[1]=1;for(i=2;i<maxn;i++){if(p[i]==0)a[++cnt]=i,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){mu[i*a[j]]=0;break;}mu[i*a[j]]=-mu[i];}}for(i=1;i<maxn;i++)sum[i]=(sum[i-1]+mu[i]*i*i%mod)%mod;scanf("%lld%lld",&n,&m);if(n>m)swp(n,m);l=1;while(l<=n){r=min(n/(n/l),m/(m/l));ans=(ans+((l+r)*(r-l+1)/2)%mod*f(n/l,m/l)%mod)%mod;l=r+1;}printf("%lld\n",ans);return 0;}
8.例题6:[SDOI2017]数字表格
题意:求
不妨设则:
首先套路地枚举:
#include<stdio.h>const int maxn=1000005;const long long mod=1000000007;int i,j,k,m,n,cnt,T,l,r;long long ans;int a[maxn],p[maxn],mu[maxn];long long f[maxn],g[maxn],mul[maxn];inline void swp(int &a,int &b){a+=b,b=a-b,a-=b;}inline int min(int a,int b){return a<b? a:b;}long long ksm(long long a,int b){long long res=1;while(b>0){if(b&1)res=(res*a)%mod;a=(a*a)%mod,b>>=1;}return res;}long long inv(long long a,long long b){return ksm(a,b-2);}int main(){p[1]=mu[1]=1;f[0]=0,f[1]=g[1]=1;for(i=2;i<maxn;i++){f[i]=(f[i-1]+f[i-2])%mod;g[i]=inv(f[i],mod);if(p[i]==0)a[++cnt]=i,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){mu[i*a[j]]=0;break;}mu[i*a[j]]=-mu[i];}}for(i=0;i<maxn;i++)mul[i]=1;for(i=1;i<maxn;i++){if(mu[i]==0)continue;for(j=i;j<maxn;j+=i){if(mu[i]==1)mul[j]=mul[j]*f[j/i]%mod;if(mu[i]==-1)mul[j]=mul[j]*g[j/i]%mod;}}for(i=2;i<maxn;i++)mul[i]=mul[i]*mul[i-1]%mod;scanf("%d",&T);while(T--){scanf("%d%d",&n,&m);if(n>m)swp(n,m);l=1,ans=1;while(l<=n){r=min(n/(n/l),m/(m/l));ans=(ans*ksm(mul[r]*inv(mul[l-1],mod)%mod,(long long)(n/l)*(long long)(m/l)%(mod-1)))%mod;l=r+1;}printf("%lld\n",(ans+mod)%mod);}return 0;}
9.例题7:[MtOI2019]幽灵乐团
我有一个绝妙的想法,但是这里空白太小,写不下
题解:[MtOI2019]幽灵乐团解题报告
#include<stdio.h>const int maxn=100005;long long i,j,k,m,n,T,p,A,B,C,l,r,cnt;long long a[maxn],c[maxn],mu[maxn],varphi[maxn],fac1[maxn],fac2[maxn],w1[maxn],f1[maxn],g1[maxn],w2[maxn],f2[maxn],g2[maxn],w3[maxn],f3[maxn],g3[maxn],sum[maxn];//a[i]={Prime},c[i]=[i\in{Prime}?]//mu[i]=(i==1?)1:((i=\prod_{j=1}^s p_i,(p_x!=p_y(x!=y)))? 0:(-1)^s)//fac1[i]=i!,fac2[i]=\prod_{j=1}^i i^i//w1[i]=\prod_{d|i}i^{\mu(d/i)},f1[i]=\prod_{j=1}^i w1[i],g1[i]=f1[i]^{-1}//w2[i]=w1[i]*(i^2),f2[i]=\prod_{j=1}^i w2[i],g2[i]=f2[i]^{-1}//w3[i]=i^{\varphi(i)},f3[i]=\prod_{j=1]^i w3[i],g3[i]=f3[i]^{-1}//sum[i]=\sum_{j=1}^i varphi[i]inline long long min(long long a,long long b){return a<b? a:b;}long long ksm(long long a,long long b,long long p){long long res=1;while(b>0){if(b&1)res=(res*a)%p;a=(a*a)%p,b>>=1;}return res;}long long inv(long long a,long long b){return ksm(a,b-2,b);}void init(){c[1]=mu[1]=varphi[1]=1;for(long long i=2;i<maxn;i++){if(c[i]==0)a[++cnt]=i,mu[i]=-1,varphi[i]=i-1;for(long long j=1;j<=cnt;j++){if(i*a[j]>=maxn)break;c[i*a[j]]=1;if(i%a[j]==0){mu[i*a[j]]=0;varphi[i*a[j]]=varphi[i]*a[j];break;}mu[i*a[j]]=-mu[i];varphi[i*a[j]]=varphi[i]*(a[j]-1);}}fac1[0]=1;for(long long i=1;i<maxn;i++)fac1[i]=fac1[i-1]*i%p;fac2[0]=1;for(long long i=1;i<maxn;i++)fac2[i]=fac2[i-1]*ksm(i,i%(p-1),p)%p;for(long long i=0;i<maxn;i++)w1[i]=w2[i]=1;for(long long i=1;i<maxn;i++){if(mu[i]==0)continue;for(long long j=i;j<maxn;j+=i){if(mu[i]==1)w1[j]=(w1[j]*(j/i))%p;if(mu[i]==-1)w1[j]=(w1[j]*inv(j/i,p))%p;}}f1[0]=g1[0]=1;for(long long i=1;i<maxn;i++)f1[i]=f1[i-1]*w1[i]%p,g1[i]=inv(f1[i],p);for(long long i=1;i<maxn;i++)w2[i]=ksm(w1[i],i*i%(p-1),p);f2[0]=g2[0]=1;for(long long i=1;i<maxn;i++)f2[i]=f2[i-1]*w2[i]%p,g2[i]=inv(f2[i],p);for(long long i=1;i<maxn;i++)w3[i]=ksm(i,varphi[i],p);f3[0]=g3[0]=1;for(long long i=1;i<maxn;i++)f3[i]=f3[i-1]*w3[i]%p,g3[i]=inv(f3[i],p);for(long long i=1;i<maxn;i++)sum[i]=sum[i-1]+varphi[i];}inline long long getsum(long long x,long long p){return x*(x+1)/2%p;}long long getnmt(long long A,long long B,long long C,long long t){if(t==0){long long res=ksm(fac1[A],B*C%(p-1),p);return res;}if(t==1){long long res=ksm(fac2[A],getsum(B,p-1)*getsum(C,p-1)%(p-1),p);return res;}if(t==2){long long l=1,r,res=1;while(l<=min(min(A,B),C)){r=min(min(A/(A/l),B/(B/l)),C/(C/l));res=res*ksm(f3[r]*g3[l-1]%p,(A/l)*(B/l)%(p-1)*(C/l)%(p-1),p)%p*ksm(fac1[A/l],(sum[r]-sum[l-1]+(p-1))%(p-1)*(B/l)%(p-1)*(C/l)%(p-1),p)%p;l=r+1;}return res;}}long long getres(long long A,long long B){long long l=1,r,res=1;while(l<=min(A,B)){r=min(A/(A/l),B/(B/l));res=res*ksm(f1[r]*g1[l-1]%p,(A/l)*(B/l)%(p-1),p)%p;l=r+1;}return res;}long long getdmt(long long A,long long B,long long C,long long t){if(t==0){long long l=1,r,res=1;while(l<=min(A,B)){r=min(A/(A/l),B/(B/l));res=(res*ksm(f1[r]*g1[l-1]%p,(A/l)*(B/l)%(p-1),p))%p;l=r+1;}return ksm(res,C,p);}if(t==1){long long l=1,r,res=1;while(l<=min(A,B)){r=min(A/(A/l),B/(B/l));res=(res*ksm(f2[r]*g2[l-1]%p,getsum(A/l,p-1)*getsum(B/l,p-1)%(p-1),p))%p;l=r+1;}return ksm(res,getsum(C,p-1),p);}if(t==2){long long l=1,r,res=1;while(l<=min(min(A,B),C)){r=min(min(A/(A/l),B/(B/l)),C/(C/l));res=res*ksm(getres(A/l,B/l),(sum[r]-sum[l-1]+(p-1))%(p-1)*(C/l)%(p-1),p)%p*ksm(f3[r]*g3[l-1]%p,(A/l)*(B/l)%(p-1)*(C/l)%(p-1),p)%p;l=r+1;}return res;}}long long getans(long long A,long long B,long long C,long long t){long long nmt=getnmt(A,B,C,t)*getnmt(B,A,C,t)%p,dmt=getdmt(A,B,C,t)*getdmt(A,C,B,t)%p;return nmt*inv(dmt,p)%p;}int main(){scanf("%lld%lld",&T,&p);init();while(T--){scanf("%lld%lld%lld",&A,&B,&C);printf("%lld %lld %lld\n",getans(A,B,C,0),getans(A,B,C,1),getans(A,B,C,2));}return 0;}
10.例题8:[SDOI2018]旧试题
题意:求其中即的因数个数
我有一个绝妙的想法,但是这里空白太小,写不下
题解:[SDOI2018]旧试题解题报告
代码:
#include<stdio.h>#include<vector>#include<string.h>using namespace std;const long long maxn=1000005,maxm=1000005,mod=1000000007;long long i,j,k,a,b,c,e,mx,mn,T,cnt,tot,ans;long long lst[maxn],d[maxn],p[maxn],mu[maxn],ok[maxn],ord[maxn],deg[maxn],f[maxn],from[maxm],to[maxm],lcm[maxm],mrk[maxn];vector<long long>v[maxn],w[maxn];inline long long min(long long a,long long b){return a<b? a:b;}inline long long max(long long a,long long b){return a>b? a:b;}inline long long gcd(long long a,long long b){return b==0? a:gcd(b,a%b);}int main(){p[1]=mu[1]=1;for(i=2;i<maxn;i++){if(p[i]==0)lst[++cnt]=i,mu[i]=-1;for(j=1;j<=cnt;j++){if(i*lst[j]>=maxn)break;p[i*lst[j]]=1;if(i%lst[j]==0){mu[i*lst[j]]=0;break;}mu[i*lst[j]]=-mu[i];}}for(i=1;i<maxn;i++)if(mu[i]!=0)ok[++tot]=i,ord[i]=tot;for(i=1;i<maxn;i++){for(j=1;i*j<maxn;j++)d[i*j]++;f[i]=(f[i-1]+d[i])%mod;}scanf("%lld",&T);while(T--){memset(deg,0,sizeof(deg));memset(v,0,sizeof(v));memset(w,0,sizeof(w));scanf("%lld%lld%lld",&a,&b,&c);mn=min(min(a,b),c),mx=max(max(a,b),c);e=ans=0;for(i=1;i<=tot;i++){if(ok[i]>mx)break;for(j=1;j<=tot;j++){if(ok[i]*ok[j]>mx)break;if(mu[ok[i]*ok[j]]==0)continue;for(k=j+1;k<=tot;k++){if(ok[i]*ok[j]*ok[k]>mx)break;if(mu[ok[i]*ok[k]]==0||gcd(ok[j],ok[k])>1)continue;from[++e]=ord[ok[i]*ok[j]],to[e]=ord[ok[i]*ok[k]],lcm[e]=ok[i]*ok[j]*ok[k];deg[from[e]]++,deg[to[e]]++;}}}for(i=1;i<=tot;i++){if(ok[i]>mn)break;ans+=mu[ok[i]]*mu[ok[i]]*mu[ok[i]]*f[a/ok[i]]*f[b/ok[i]]*f[c/ok[i]];}for(i=1;i<=e;i++){v[from[i]].push_back(to[i]),w[from[i]].push_back(lcm[i]);v[to[i]].push_back(from[i]),w[to[i]].push_back(lcm[i]);}for(i=1;i<=tot;i++){if(ok[i]>min(a,b))break;for(j=0;j<v[i].size();j++){long long x=ok[i],y=ok[v[i][j]],z=w[i][j];ans=(ans+mu[x]*mu[y]*mu[y]*f[a/z]*f[b/z]*f[c/y]%mod+mod)%mod;ans=(ans+mu[x]*mu[x]*mu[y]*f[a/x]*f[b/z]*f[c/z]%mod+mod)%mod;ans=(ans+mu[x]*mu[x]*mu[y]*f[a/z]*f[b/x]*f[c/z]%mod+mod)%mod;}}memset(v,0,sizeof(v));memset(w,0,sizeof(w));for(i=1;i<=e;i++){if(deg[from[i]]>=deg[to[i]])v[from[i]].push_back(to[i]),w[from[i]].push_back(lcm[i]);else v[to[i]].push_back(from[i]),w[to[i]].push_back(lcm[i]);}for(i=1;i<=tot;i++){if(ok[i]>mx)break;for(j=0;j<v[i].size();j++)mrk[v[i][j]]=w[i][j];for(j=0;j<v[i].size();j++){long long x=v[i][j];for(k=0;k<v[x].size();k++){long long y=v[x][k],p=mrk[y],q=w[i][j],r=w[x][k];if(mrk[y]==0)continue;long long st1,st2,st3,st4,st5,st6;st1=f[a/p]*f[b/q]*f[c/r]%mod;st2=f[a/p]*f[b/r]*f[c/q]%mod;st3=f[a/q]*f[b/p]*f[c/r]%mod;st4=f[a/q]*f[b/r]*f[c/p]%mod;st5=f[a/r]*f[b/p]*f[c/q]%mod;st6=f[a/r]*f[b/q]*f[c/p]%mod;ans=(ans+mu[ok[i]]*mu[ok[x]]*mu[ok[y]]*(st1+st2+st3+st4+st5+st6)%mod+mod)%mod;}}for(j=0;j<v[i].size();j++)mrk[v[i][j]]=0;}printf("%lld\n",(ans+mod)%mod);}return 0;}
11.例题9:P4240 毒瘤之神的考验
题意:求
我有一个绝妙的想法,但是这里空白太小,写不下
题解:P4240 毒瘤之神的考验解题报告
#include<stdio.h>#include<vector>#define int long longusing namespace std;const int maxn=100005,mod=998244353,maxt=55;int T,n,m,cnt,t;int a[maxn],p[maxn],miu[maxn],phi[maxn],nphi[maxn],f[maxn];vector<int>g[maxn],S[maxt][maxt];int ksm(int a,int b){int res=1;while(b){if(b&1)res=res*a%mod;a=a*a%mod,b>>=1;}return res;}void init(){t=50;p[1]=miu[1]=phi[1]=1;for(int i=2;i<maxn;i++){if(p[i]==0)a[++cnt]=i,miu[i]=-1,phi[i]=i-1;for(int j=1;j<=cnt;j++){if(i*a[j]>=maxn)break;p[i*a[j]]=1;if(i%a[j]==0){miu[i*a[j]]=0;phi[i*a[j]]=phi[i]*a[j];break;}miu[i*a[j]]=-miu[i];phi[i*a[j]]=phi[i]*(a[j]-1);}}for(int i=1;i<maxn;i++)nphi[i]=ksm(phi[i],mod-2);for(int i=1;i<maxn;i++)for(int j=1;i*j<maxn;j++)f[i*j]=(f[i*j]+i*nphi[i]%mod*miu[j])%mod;for(int i=1;i<maxn;i++){g[i].push_back(0);for(int j=1;i*j<maxn;j++)g[i].push_back((g[i][j-1]+phi[i*j])%mod);}for(int i=1;i<=t;i++)for(int j=1;j<=t;j++){S[i][j].push_back(0);for(int k=1;k*max(i,j)<maxn;k++)S[i][j].push_back((S[i][j][k-1]+f[k]*g[k][i]%mod*g[k][j]%mod)%mod);}}int solve(int n,int m){int res=0,l,r;for(int i=1;i<=max(n,m)/t;i++)res=(res+f[i]*g[i][n/i]%mod*g[i][m/i]%mod)%mod;l=max(n,m)/t+1;while(l<=min(n,m)){r=min(n/(n/l),m/(m/l));res=(res+(S[n/l][m/l][r]-S[n/l][m/l][l-1]+mod)%mod)%mod;l=r+1;}return res;}signed main(){init();scanf("%lld",&T);while(T--){scanf("%lld%lld",&n,&m);printf("%lld\n",solve(n,m));}return 0;}
完结撒花!
续集:杜教筛学习笔记