[关闭]
@ZYK1997 2015-04-02T03:53:20.000000Z 字数 8143 阅读 1232

数论练习题

数论


Prob 1:

给你 N,M,求 ∑Na=1∑Mb=1gcd(a,b)

思路一:∑d∣nφ(d)=n

推导如下:

∑a=1N∑b=1Mgcd(a,b)

=∑a=1N∑b=1M∑d∣gcd(a,b)φ(d)

=∑dφ(d)⋅∑a=1N∑b=1M[d∣gcd(a,b)]

=∑dφ(d)⋅∑a=1N∑b=1M[d∣a ∧ d∣b]

=∑dφ(d)⋅∑a=1N[d∣a]⋅∑b=1M[d∣b]

=∑dφ(d)⋅⌊Nd⌋⋅⌊Md⌋

化简到这里,我们不禁想起了另一道经典题目:
给定n,求 ∑Ni=1⌊Ni⌋
解决方法:通过观察(打表)、猜想……我们可以发现,对于很多i而言,⌊Ni⌋的值是相等的。不妨设 ∀i∈[l,r],⌊Ni⌋=d,那么∑ri=l⌊Ni⌋=d∗∑ri=l,然而,我们可以证明[l,r]这样的区间总共不超过N−−√个,问题可以在O(N−−√)内解决。

我们再回到这道题来。
我们会发现,⌊Nd⌋和⌊Md⌋,分别有N−−√,M−−√个区间,那么⌊Nd⌋⋅⌊Md⌋取值不超过N−−√+M−−√个区间,我们可以预处理出来φ(d)的前缀和,然后枚举区间,问题可以在O(N−−√+M−−√)解决。
粘上代码:

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. const int N=100000,M=N+5;
  4. #define LL long long
  5. int n,m;
  6. bool cjx[M];
  7. int prime[M],tot;
  8. int phi[M];
  9. LL sum[M];
  10. void pre(){
  11. tot=0;
  12. phi[1]=1;
  13. for(int i=2;i<=N;i++){
  14. if(!cjx[i]) {
  15. prime[tot++]=i;
  16. phi[i]=i-1;
  17. }
  18. for(int j=0;j<tot;j++){
  19. if(i*prime[j]>N) break;
  20. cjx[i*prime[j]]=true;
  21. if(i%prime[j]==0){
  22. phi[i*prime[j]]=phi[i]*prime[j];
  23. break;
  24. } else {
  25. phi[i*prime[j]]=phi[i]*(prime[j]-1);
  26. }
  27. }
  28. }
  29. for(int i=1;i<=N;i++) sum[i]=sum[i-1]+phi[i];
  30. }
  31. LL solve(int n,int m){
  32. LL re=0;
  33. for(int i=1,j;i<=min(n,m);i=j+1){
  34. j=min(n/(n/i),m/(m/i));
  35. re+=(sum[j]-sum[i-1])*(n/i)*(m/i);
  36. }
  37. return re;
  38. }
  39. int main(){
  40. pre();
  41. int T; scanf("%d",&T);
  42. while(T--){
  43. scanf("%d%d",&n,&m);
  44. cout<<solve(n,m)<<endl;
  45. }
  46. return 0;
  47. }

思路二:∑d∣nμ(d)=[n=1]

我们换一个思路,考虑d可能成为哪些i,j的最大公约数

∑i=1N∑j=1Mgcd(i,j)

=∑i=1N∑j=1M∑d[d=gcd(i,j)]d

=∑dd⋅∑i=1N∑j=1M[d=gcd(i,j)]

=∑dd⋅∑i=1⌊Nd⌋∑j=1⌊Md⌋[gcd(i,j)=1]

=∑dd⋅∑i=1⌊Nd⌋∑j=1⌊Md⌋∑d′∣gcd(i,j)μ(d′)

=∑dd⋅∑d′μ(d′)∑i=1⌊Nd⌋[d′∣i]∑j=1⌊Md⌋[d′∣j]

=∑dd⋅∑d′μ(d′)⋅⌊⌊Nd⌋d′⌋⋅⌊⌊Md⌋d′⌋

=∑dd⋅∑d′μ(d′)⋅⌊Nd⋅d′⌋⋅⌊Md⋅d′⌋

我们设D=d⋅d′,那么d=Dd′
ans=∑D⌊ND⌋⋅⌊MD⌋⋅∑d∣Dμ(d)⋅Dd

我们发现后面的H(x)=∑d∣xμ(d)⋅xd是f(x)=μ(x)和g(x)=x的狄利克雷卷积,所以H(x)是积性函数,我们可以使用筛法O(N)预处理出来,剩下过程和思路一相同了。
到了这里,不知道大家有没有发现,和思路一对比之下,我们发现,H(x)=φ(x),没错!
这是巧合吗?不!
n=∑d∣nφ(d)
我们设f(x)=x,g(x)=φ(x)
则f(x)=∑d∣xg(d),
我们进行莫比乌斯反演得到:
g(x)=∑d∣xμ(d)⋅f(xd)
也就是
φ(x)=∑d∣xμ(d)⋅xd
我们结合思路一与思路二无意中发现了莫比乌斯反演,哈哈哈。。。


Prob 2:

给你 N,M,求∑Na=1∑Mb=1lcm(a,b)

主要公式:∑d∣nμ(d)=[n=1]

推导如下:

∑a=1N∑b=1Mlcm(a,b)

=∑a=1N∑b=1Ma⋅bgcd(a,b)

=∑a=1N  ∑b=1,d=gcd(a,b)Ma⋅bd

=∑d∑a=1N∑b=1Ma⋅bd⋅[d=gcd(a,b)]

=∑dd⋅∑a=1⌊Nd⌋∑b=1⌊Md⌋a⋅b⋅[gcd(a,b)=1]

不妨设f(n,m)=∑na=1∑mb=1a⋅b⋅[gcd(a,b)=1]
下面化简f(n,m)=
∑a=1n∑b=1ma⋅b⋅[gcd(a,b)=1]

=∑a=1n∑b=1ma⋅b⋅∑d∣gcd(a,b)μ(d)

=∑dμ(d)∑d∣an∑d∣bma⋅b

=∑dμ(d)∑a=1⌊nd⌋∑b=1⌊md⌋a⋅b⋅d2

=∑dμ(d)⋅d2∑a=1⌊nd⌋∑b=1⌊md⌋a⋅b

=∑dμ(d)⋅d2⋅⌊nd⌋⋅(⌊nd⌋+1)2⋅⌊md⌋⋅(⌊md⌋+1)2

下面我们把f(⌊Nd⌋,⌊Md⌋)代入原式:ans=
14∑dd⋅∑d′μ(d′)⋅d′2⋅⌊⌊Nd⌋d′⌋⋅(⌊⌊Nd⌋d′⌋+1)⋅⌊⌊Md⌋d′⌋⋅(⌊⌊Md⌋d′⌋+1)

=14∑dd⋅∑d′μ(d′)⋅d′2⋅⌊Nd⋅d′⌋⋅(⌊Nd⋅d′⌋+1)⋅⌊Md⋅d′⌋⋅(⌊Md⋅d′⌋+1)

令D=d⋅d′
=14∑D⌊ND⌋⋅(⌊ND⌋+1)⋅⌊MD⌋⋅(⌊MD⌋+1)⋅D∑d∣Dμ(d)⋅d

由于积性函数的莫比乌斯变换函数还是积性函数,所以D∑d∣Dμ(d)⋅d是积性函数,可以用筛法O(N),预处理出来。我们再观察前面14∑D⌊ND⌋⋅(⌊ND⌋+1)⋅⌊MD⌋⋅(⌊MD⌋+1)这一堆东西,很明显还是分块来搞。
这样一来,问题最终O(N−−√+M−−√)完美解决。
粘上代码:

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. const int N=100000;
  4. const int M=100005;
  5. typedef long long LL;
  6. bool cjx[M];
  7. int prime[M],tot;
  8. int mu[M];
  9. LL g[M],sum[M];
  10. void pre(){
  11. tot=0;
  12. mu[1]=1; g[1]=1;
  13. for(int i=2;i<=N;i++){
  14. if(!cjx[i]){
  15. prime[tot++]=i;
  16. mu[i]=-1;
  17. g[i]=-i*(i-1);
  18. }
  19. for(int j=0;j<tot;j++){
  20. if(i*prime[j]>N) break;
  21. cjx[i*prime[j]]=true;
  22. if(i%prime[j]==0){
  23. mu[i*prime[j]]=0;
  24. g[i*prime[j]]=g[i]*prime[j];
  25. break;
  26. } else {
  27. mu[i*prime[j]]=-mu[i];
  28. g[i*prime[j]]=g[i]*g[prime[j]];
  29. }
  30. }
  31. }
  32. for(int i=1;i<=N;i++) sum[i]=sum[i-1]+g[i];
  33. }
  34. LL solve(int n,int m){
  35. LL re=0;
  36. for(int i=1,j;i<=min(n,m);i=j+1){
  37. j=min(n/(n/i),m/(m/i));
  38. re+=(LL)(sum[j]-sum[i-1])*(n/i)*(n/i+1)*(m/i)*(m/i+1);
  39. }
  40. return re>>2;
  41. }
  42. int main(){
  43. pre();
  44. int T; scanf("%d",&T);
  45. while(T--){
  46. int n,m;
  47. scanf("%d%d",&n,&m);
  48. cout<<solve(n,m)<<endl;
  49. }
  50. return 0;
  51. }

Prob 3

给你 n,求 ∑ni=1gcd(i,n)

解析:
首先转化思路,我们思考d可以成为哪些i与n的最大公约数
∑ni=1gcd(i,n)=∑d∣nd⋅φ(nd)
设f(x)=x,g(x)=φ(x),H(x)=∑d∣nd⋅φ(nd)
则H(x)是f(x)和g(x)的狄利克雷卷积,所以H(x)是积性函数。
我们将n分解质因数
H(n)=H(pα11⋅pα22⋅…⋅pαnn)=H(pα11)⋅H(pα22)⋅…⋅H(pαnn)
所以我们只需要思考怎么计算H(pk)即可。
H(pk)=∑d∣pkd⋅φ(pkd)
=∑ki=0pi⋅φ(pk−i)
而我们知道φ(pk)=pk−pk−1
那么我们通过数列化简、整理最终得到
H(pk)=(k+1)⋅pk−k⋅pk−1
问题解决了,我的代码比较丑,大家意识流即可……

  1. #include<iostream>
  2. #include<cstring>
  3. #include<cstdio>
  4. #include<cmath>
  5. #include<algorithm>
  6. using namespace std;
  7. typedef long long LL;
  8. LL pow(LL a,LL b){
  9. LL re=1;
  10. for(;b;b>>=1,a*=a)
  11. if(b&1) re*=a;
  12. return re;
  13. }
  14. int main(){
  15. LL n; cin>>n;
  16. LL ans=1;
  17. for(int i=2;i*i<=n;i++){
  18. LL a=0;
  19. while(n%i==0){
  20. a++; n/=i;
  21. }
  22. if(a==0) continue;
  23. LL b=pow(i,a-1);
  24. ans*=(a+1)*b*i-a*b;
  25. }
  26. ans*=2*n-1;
  27. cout<<ans<<endl;
  28. return 0;
  29. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注