[关闭]
@xiaoziyao 2020-10-13T18:23:24.000000Z 字数 4553 阅读 1157

P4240 毒瘤之神的考验解题报告

解题报告


注:集合为质数集。

P4240 毒瘤之神的考验解题报告:

更好的阅读体验

题意

分析

莫比乌斯反演结合根号分治好题。

首先,欧拉函数有一个性质:

证明如下:

由欧拉函数的公式有:


我们根据容斥的思想可以得到:

,然后我们就可以带入最开始的式子推一下:

然后枚举(不妨设

这个式子并不好处理,可以先设,然后原式化为:

很容易处理,直接枚举因数,然后就可以用总体的复杂度解决。

关于,我们可以得到一个很显然的递推式:

不妨再设,同样

但是的大小均可以到达,因此预处理是不可行的,那么预处理更不行了。

考虑根号分治,我们设一个阈值,那么把答案分成两部分考虑:

总复杂度为左右可过。

代码

  1. #include<stdio.h>
  2. #include<vector>
  3. #define int long long
  4. using namespace std;
  5. const int maxn=100005,mod=998244353,maxt=55;
  6. int T,n,m,cnt,t;
  7. int a[maxn],p[maxn],miu[maxn],phi[maxn],nphi[maxn],f[maxn];
  8. vector<int>g[maxn],S[maxt][maxt];
  9. int ksm(int a,int b){
  10. int res=1;
  11. while(b){
  12. if(b&1)
  13. res=res*a%mod;
  14. a=a*a%mod,b>>=1;
  15. }
  16. return res;
  17. }
  18. void init(){
  19. t=50;
  20. p[1]=miu[1]=phi[1]=1;
  21. for(int i=2;i<maxn;i++){
  22. if(p[i]==0)
  23. a[++cnt]=i,miu[i]=-1,phi[i]=i-1;
  24. for(int j=1;j<=cnt;j++){
  25. if(i*a[j]>=maxn)
  26. break;
  27. p[i*a[j]]=1;
  28. if(i%a[j]==0){
  29. miu[i*a[j]]=0;
  30. phi[i*a[j]]=phi[i]*a[j];
  31. break;
  32. }
  33. miu[i*a[j]]=-miu[i];
  34. phi[i*a[j]]=phi[i]*(a[j]-1);
  35. }
  36. }
  37. for(int i=1;i<maxn;i++)
  38. nphi[i]=ksm(phi[i],mod-2);
  39. for(int i=1;i<maxn;i++)
  40. for(int j=1;i*j<maxn;j++)
  41. f[i*j]=(f[i*j]+i*nphi[i]%mod*miu[j])%mod;
  42. for(int i=1;i<maxn;i++){
  43. g[i].push_back(0);
  44. for(int j=1;i*j<maxn;j++)
  45. g[i].push_back((g[i][j-1]+phi[i*j])%mod);
  46. }
  47. for(int i=1;i<=t;i++)
  48. for(int j=1;j<=t;j++){
  49. S[i][j].push_back(0);
  50. for(int k=1;k*max(i,j)<maxn;k++)
  51. S[i][j].push_back((S[i][j][k-1]+f[k]*g[k][i]%mod*g[k][j]%mod)%mod);
  52. }
  53. }
  54. int solve(int n,int m){
  55. int res=0,l,r;
  56. for(int i=1;i<=max(n,m)/t;i++)
  57. res=(res+f[i]*g[i][n/i]%mod*g[i][m/i]%mod)%mod;
  58. l=max(n,m)/t+1;
  59. while(l<=min(n,m)){
  60. r=min(n/(n/l),m/(m/l));
  61. res=(res+(S[n/l][m/l][r]-S[n/l][m/l][l-1]+mod)%mod)%mod;
  62. l=r+1;
  63. }
  64. return res;
  65. }
  66. signed main(){
  67. init();
  68. scanf("%lld",&T);
  69. while(T--){
  70. scanf("%lld%lld",&n,&m);
  71. printf("%lld\n",solve(n,m));
  72. }
  73. return 0;
  74. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注