https://www.luogu.org/problemnew/show/P2398

$原式=\sum_{k=1}^n(k\sum_{i=1}^n\sum_{j=1}^n[(i,j)=k])$

方法1:

发现暴力枚举k,就变成这道模板题

复杂度O(nlogn)

  1. #pragma GCC optimize("Ofast")
  2. #include<cstdio>
  3. #include<algorithm>
  4. #include<cstring>
  5. #include<vector>
  6. using namespace std;
  7. #define fi first
  8. #define se second
  9. #define mp make_pair
  10. #define pb push_back
  11. typedef long long ll;
  12. typedef unsigned long long ull;
  13. typedef pair<int,int> pii;
  14. #define N 2000000
  15. ll prime[N+],len,mu[N+];
  16. bool nprime[N+];
  17. ll n,ans,a2;
  18. ll F(ll x) {return (n/x)*(n/x);}
  19. int main()
  20. {
  21. ll i,j,k;
  22. mu[]=;
  23. for(i=;i<=N;i++)
  24. {
  25. if(!nprime[i]) prime[++len]=i,mu[i]=-;
  26. for(j=;j<=len&&i*prime[j]<=N;j++)
  27. {
  28. nprime[i*prime[j]]=;
  29. if(i%prime[j]==) {mu[i*prime[j]]=;break;}
  30. else mu[i*prime[j]]=-mu[i];
  31. }
  32. }
  33. scanf("%lld",&n);
  34. for(k=;k<=n;k++)
  35. {
  36. a2=;
  37. for(i=;i<=n/k;i++)
  38. a2+=mu[i]*F(i*k);
  39. ans+=a2*k;
  40. }
  41. printf("%lld",ans);
  42. return ;
  43. }

方法2:

https://www.luogu.org/blog/Cinema/solution-p1390

(这是一道类似的题的题解)

复杂度好像是O(n)

具体地说,是嵌套整除分块,第一重枚举n/d,m/d,第二重枚举(n/d)/x,(m/d)/x


方法3:

$\sum_{i=1}^n\sum_{j=1}^n[(i,j)=k]=\sum_{i=1}^{{\lfloor}n/k{\rfloor}}\sum_{j=1}^{{\lfloor}n/k{\rfloor}}[(i,j)=1]$

$=2*(\sum_{i=1}^{{\lfloor}n/k{\rfloor}}\sum_{j=1}^{i}[(i,j)=1])-1=2*(\sum_{i=1}^{{\lfloor}n/k{\rfloor}}\varphi(i))-1$

这个欧拉函数的前缀和可以先预处理出来,然后枚举k

复杂度O(n)

  1. #include<cstdio>
  2. #include<algorithm>
  3. #include<cstring>
  4. #include<vector>
  5. using namespace std;
  6. #define fi first
  7. #define se second
  8. #define mp make_pair
  9. #define pb push_back
  10. typedef long long ll;
  11. typedef unsigned long long ull;
  12. typedef pair<int,int> pii;
  13. #define N 2000000
  14. ll prime[N+],len,phi[N+];
  15. ll d[N+];
  16. bool nprime[N+];
  17. ll n,ans;
  18. ll F(ll x) {return (n/x)*(n/x);}
  19. int main()
  20. {
  21. ll i,j,k;
  22. phi[]=;
  23. for(i=;i<=N;i++)
  24. {
  25. if(!nprime[i]) prime[++len]=i,phi[i]=i-;
  26. for(j=;j<=len&&i*prime[j]<=N;j++)
  27. {
  28. nprime[i*prime[j]]=;
  29. if(i%prime[j]==) {phi[i*prime[j]]=phi[i]*prime[j];break;}
  30. else phi[i*prime[j]]=phi[i]*(prime[j]-);
  31. }
  32. }
  33. for(i=;i<=N;i++) d[i]+=d[i-]+phi[i];
  34. scanf("%lld",&n);
  35. for(k=;k<=n;k++) ans+=k*(*d[n/k]-);
  36. printf("%lld",ans);
  37. return ;
  38. }

方法4:

注意到方法3第35行的可以用整除分块优化,甚至可以O(n)预处理后每次O(sqrt(n))回答


类似的题(题面并不完全一样)

https://www.luogu.org/problemnew/show/UVA11417

https://www.luogu.org/problemnew/show/UVA11426

https://www.luogu.org/problemnew/show/P1390


https://www.luogu.org/problemnew/show/UVA11424

这题做法稍微有点不一样,因为数据组数多,不能直接每次O(n)回答

可以用方法4水过去

  1. #include<cstdio>
  2. #include<algorithm>
  3. #include<cstring>
  4. #include<vector>
  5. using namespace std;
  6. #define fi first
  7. #define se second
  8. #define mp make_pair
  9. #define pb push_back
  10. typedef long long ll;
  11. typedef unsigned long long ull;
  12. typedef pair<int,int> pii;
  13. #define N 2000000
  14. ll prime[N+],len,phi[N+];
  15. ll d[N+];
  16. bool nprime[N+];
  17. ll n,ans;
  18. ll F(ll x) {return (n/x)*(n/x);}
  19. int main()
  20. {
  21. ll i,j,k;
  22. phi[]=;
  23. for(i=;i<=N;i++)
  24. {
  25. if(!nprime[i]) prime[++len]=i,phi[i]=i-;
  26. for(j=;j<=len&&i*prime[j]<=N;j++)
  27. {
  28. nprime[i*prime[j]]=;
  29. if(i%prime[j]==) {phi[i*prime[j]]=phi[i]*prime[j];break;}
  30. else phi[i*prime[j]]=phi[i]*(prime[j]-);
  31. }
  32. }
  33. for(i=;i<=N;i++) d[i]+=d[i-]+phi[i];
  34. while(){
  35. scanf("%lld",&n);
  36. if(n==) break;
  37. ans=;
  38. for(i=;i<=n;i=j+)
  39. {
  40. j=min(n,n/(n/i));
  41. ans+=(i+j)*(j-i+)/*(*d[n/i]-);
  42. }
  43. printf("%lld\n",(ans-(n+)*n/)/);}
  44. return ;
  45. }

或者:

设sum[x]=$\sum_{i=1}^{x-1}(i,x)$

那么询问为n时,答案就是$\sum_{i=1}^n{sum[i]}$

而sum[x]=$\sum_{k=1}^{x-1}(k*\sum_{i=1}^{x-1}[(i,x)=k])$

显然只有当k是x的因子且k不等于x时才能有贡献

枚举k,$\sum_{i=1}^{x-1}[(i,x)=k]=\sum_{i=1}^{\frac{x}{k}-1}[(i,\frac{x}{k})=1]$

$=(\sum_{i=1}^{\frac{x}{k}}[(i,\frac{x}{k})=1])=\phi(\frac{x}{k})$

可以看出来sum[x]=$(\sum_{d|x且d{\neq}x}(d*\phi(\frac{x}{d})))$

实际实现时可以把枚举因子变为枚举倍数

复杂度所有数据加起来O(nlogn+q)

  1. #include<cstdio>
  2. #include<algorithm>
  3. #include<cstring>
  4. #include<vector>
  5. using namespace std;
  6. #define fi first
  7. #define se second
  8. #define mp make_pair
  9. #define pb push_back
  10. typedef long long ll;
  11. typedef unsigned long long ull;
  12. typedef pair<int,int> pii;
  13. #define N 200000
  14. ll prime[N+],len,phi[N+];
  15. ll sum[N+];
  16. bool nprime[N+];
  17. ll n,ans[N+];
  18. int main()
  19. {
  20. ll i,j,k;
  21. phi[]=;
  22. for(i=;i<=N;i++)
  23. {
  24. if(!nprime[i]) prime[++len]=i,phi[i]=i-;
  25. for(j=;j<=len&&i*prime[j]<=N;j++)
  26. {
  27. nprime[i*prime[j]]=;
  28. if(i%prime[j]==) {phi[i*prime[j]]=phi[i]*prime[j];break;}
  29. else phi[i*prime[j]]=phi[i]*(prime[j]-);
  30. }
  31. }
  32. for(i=;i<=N;i++)
  33. for(j=*i;j<=N;j+=i)
  34. sum[j]+=i*phi[j/i];
  35. for(i=;i<=N;i++) ans[i]=ans[i-]+sum[i];
  36. while(){
  37. scanf("%lld",&n);
  38. if(n==) break;
  39. printf("%lld\n",ans[n]);
  40. }
  41. return ;
  42. }

https://www.luogu.org/problemnew/show/P2257

事实上此题做法与以上几题是一样的,如果数据范围一样。。

然而此题有多组数据又是1e7,需要更好的做法

不妨设n<=m

根据方法2,得到答案是$\sum_{1<=k<=n且k为质数}\sum_{i=1}^n\mu(i){\lfloor}\frac{n}{ik}{\rfloor}{\lfloor}\frac{m}{ik}{\rfloor}$

好像不能化简了?然而A不了题?

强行解释一波推算方法:注意到最终的可能求法是整除分块,要枚举ik的积,那么试着把它提出来

第二种解释方法:为什么要这么写式子?学莫比乌斯反演时学来的式子枚举的就是d啊

看了题解,发现可以令d=ik

答案就等于$\sum_{1<=k<=n且k为质数}\sum_{k|d}\mu(\frac{d}{k}){\lfloor}\frac{n}{d}{\rfloor}{\lfloor}\frac{m}{d}{\rfloor}$

$=\sum_{d=1}^n\sum_{k|d且k为质数}\mu(\frac{d}{k}){\lfloor}\frac{n}{d}{\rfloor}{\lfloor}\frac{m}{d}{\rfloor}$

$\sum_{k|d且k为质数}\mu(\frac{d}{k})$可以预处理了,根据那个质数个数(近似)公式,预处理复杂度大概接近O(n)了。。

可以A了。。。

  1. //#pragma GCC optimize("Ofast")
  2. #include<cstdio>
  3. #include<algorithm>
  4. #include<cstring>
  5. #include<vector>
  6. using namespace std;
  7. #define fi first
  8. #define se second
  9. #define mp make_pair
  10. #define pb push_back
  11. typedef long long ll;
  12. typedef unsigned long long ull;
  13. typedef pair<int,int> pii;
  14. #define N 10000000
  15. int prime[N+],len,mu[N+],dd[N+];
  16. bool nprime[N+];
  17. int n,m;ll ans;
  18. int main()
  19. {
  20. int i,j,k,T,TT;
  21. mu[]=;
  22. for(i=;i<=N;i++)
  23. {
  24. if(!nprime[i]) prime[++len]=i,mu[i]=-;
  25. for(j=;j<=len&&i*prime[j]<=N;j++)
  26. {
  27. nprime[i*prime[j]]=;
  28. if(i%prime[j]==) {mu[i*prime[j]]=;break;}
  29. else mu[i*prime[j]]=-mu[i];
  30. }
  31. }
  32. for(i=;i<=len;i++)
  33. for(j=,k=prime[i];j<=N/prime[i];j++,k+=prime[i])
  34. dd[k]+=mu[j];
  35. for(i=;i<=N;i++) dd[i]+=dd[i-];
  36. scanf("%d",&T);
  37. for(TT=;TT<=T;TT++)
  38. {
  39. scanf("%d%d",&n,&m);
  40. if(n>m) swap(n,m);
  41. ans=;
  42. for(i=;i<=n;i=j+)
  43. {
  44. j=min(n,min(n/(n/i),m/(m/i)));
  45. ans+=ll(dd[j]-dd[i-])*(n/i)*(m/i);
  46. }
  47. printf("%lld\n",ans);
  48. }
  49. return ;
  50. }

双倍经验https://www.luogu.org/problemnew/show/P2568

好吧以上这题时限有点紧。。不过单次询问O(n)也可以用方法3或者方法2

洛谷 P2398 GCD SUM || uva11417,uva11426,uva11424,洛谷P1390,洛谷P2257,洛谷P2568的更多相关文章

  1. 洛谷P2398 GCD SUM (数学)

    洛谷P2398 GCD SUM 题目描述 for i=1 to n for j=1 to n sum+=gcd(i,j) 给出n求sum. gcd(x,y)表示x,y的最大公约数. 输入输出格式 输入 ...

  2. 洛谷P2398 GCD SUM [数论,欧拉筛]

    题目传送门 GCD SUM 题目描述 for i=1 to n for j=1 to n sum+=gcd(i,j) 给出n求sum. gcd(x,y)表示x,y的最大公约数. 输入输出格式 输入格式 ...

  3. 洛谷P2398 GCD SUM

    题目描述 for i=1 to n for j=1 to n sum+=gcd(i,j) 给出n求sum. gcd(x,y)表示x,y的最大公约数. 输入输出格式 输入格式: n 输出格式: sum ...

  4. 洛谷 P2398 GCD SUM 题解

    题面 挺有意思的. 设f[i]表示gcd(i,j)=i的个数,g[i]表示k|gcd(i,j)的个数; g[i]=(n/i)*(n/i); g[i]=f[i]+f[2i]+f[3i]+...; 所以f ...

  5. P2398 GCD SUM

    P2398 GCD SUM一开始是憨打表,后来发现打多了,超过代码长度了.缩小之后是30分,和暴力一样.正解是,用f[k]表示gcd为k的一共有多少对.ans=sigma k(1->n) k*f ...

  6. *P2398 GCD SUM[数论]

    题目描述 for i=1 to n for j=1 to n sum+=gcd(i,j) 解析 给出n求sum. gcd(x,y)表示x,y的最大公约数. 直接枚举复杂度为\(O(n^2)\),显然无 ...

  7. acdream 1148 GCD SUM 莫比乌斯反演 ansx,ansy

    GCD SUM Time Limit: 8000/4000MS (Java/Others)Memory Limit: 128000/64000KB (Java/Others) SubmitStatis ...

  8. GCD SUM 强大的数论,容斥定理

    GCD SUM Time Limit: 8000/4000MS (Java/Others) Memory Limit: 128000/64000KB (Java/Others) SubmitStatu ...

  9. Luogu2398 GCD SUM

    Luogu2398 GCD SUM 求 \(\displaystyle\sum_{i=1}^n\sum_{j=1}^n\gcd(i,j)\) \(n\leq10^5\) 数论 先常规化式子(大雾 \[ ...

随机推荐

  1. directdraw 显示yuv

    http://www.cnblogs.com/lidan/archive/2012/03/23/2413772.html http://www.yirendai.com/msd/

  2. POJ 2886 Who Gets the Most Candies?(树状数组+二分)

    题目链接 注意题目中给的顺序是顺时针的,所以在数组中应该是倒着存的.左就是顺时针,右就是逆时针.各种调试之后,终于A了,很多种情况考虑情况. #include <cstring> #inc ...

  3. armel、armhf和arm64

    1 这些名词是什么的缩写 1.1 armel 是arm eabi little endian的缩写.eabi是软浮点二进制接口,这里的e是embeded,是对于嵌入式设备而言. 1.2 armhf 是 ...

  4. Java客户端:调用EyeKey HTTP接口进行人脸对比

    package com.example.buyishi; import java.io.BufferedReader; import java.io.IOException; import java. ...

  5. gravity layout_gravity

    gravity:控制当前视图的内容/子view layout_gravity:控制视图本身

  6. js-easyUI格式化时间

    formatter : function(value, row) { if(value != null){ var date = new Date(value); var y = date.getFu ...

  7. A喝酒(北京林业大学校赛)

    http://www.jisuanke.com/contest/1410 王大钉喜欢喝酒,存货都喝完了,他就去楼下买,正好楼下的商店为了响应学校的 ACM 校赛推出了优惠活动:凡是在本店买的啤酒,喝完 ...

  8. i2c_set_clientdata函数【转】

    本文转载自‘:http://blog.csdn.net/jk198310/article/details/43738367 在i2c驱动中有很多函数和数据结构,很多一时难以理解,所以写下本文共同学习. ...

  9. fork函数的使用【学习笔记】

    #include "apue.h" ; char buf[] = "a write to stdout\r\n"; int main(void) { int v ...

  10. HDU3507 Print Article —— 斜率优化DP

    题目链接:https://vjudge.net/problem/HDU-3507 Print Article Time Limit: 9000/3000 MS (Java/Others)    Mem ...