[关闭]
@xiaoziyao 2021-01-23T14:44:31.000000Z 字数 5865 阅读 864

CF235E Number Challenge解题报告

解题报告


CF235E Number Challenge解题报告:

更好的阅读体验

题意

分析

第一眼就看出来好像见过这道题,然后想起来它是P4619 [SDOI2018]旧试题的弱化版到底是CCF抄CF的还是CF抄CCF的呢

我们先证明一个毒瘤式子

因为的因数个数,因此考虑将的每个因数对应一组互质的因数

对于每个质数,且的幂次为的幂次为的幂次为,则的幂次为

根据的积性与,得:,即对左式的贡献为

,则的幂次不超过的幂次不超过的幂次不超过,且中起码有两个为

即每个可以对右式同样产生的贡献,因此对于每个的质因子,其会对左右两式均产生的指数的贡献

因此我们可以把原式化为:

改变枚举顺序可得:

使用莫比乌斯反演得原式可得:

继续交换枚举顺序得:

由引理得:,原式化为:

,考虑如何预处理:对于每一个都会得到的贡献,即在的范围内的倍数个数。

因此即约数和函数,这个函数通过可以枚举每个数的倍数在的时间内预处理。

原式可化为:

但是最后的式子还是的,就比暴力快一点点。

首先,我们可以把所有删去,这种有不少,因此可以快很多。

其次,因为,因此所有的可以剪掉。(其实不剪掉也没有关系,对答案没有影响,因此我们将统一改为

为了达到更低的复杂度,我们可以使用一种毒瘤算法:三元环计数。感性理解一下,枚举三个数,且满足就相当于在一张只要任意两个点满足其最小公倍数小于等于边会有一条边的图中枚举三元环。

三元环计数算法可以在的时间内求出所有三元环,具体见nekko的博客:不常用的黑科技——「三元环」

时间复杂度:

代码

直接拿的旧试题的代码,加了亿点常数优化,凑合着看吧。

  1. #include<stdio.h>
  2. #include<vector>
  3. #include<string.h>
  4. #define int long long
  5. using namespace std;
  6. const int maxn=1000005,maxm=1000005,mod=1073741824;
  7. int i,j,k,a,b,c,e,mx,mn,T,cnt,tot,ans;
  8. int lst[maxn],d[maxn],p[maxn],mu[maxn],ok[maxn],ord[maxn],deg[maxn],f[maxn],from[maxm],to[maxm],lcm[maxm],mrk[maxn];
  9. vector<int>v[maxn],w[maxn];
  10. inline int min(int a,int b){
  11. return a<b? a:b;
  12. }
  13. inline int max(int a,int b){
  14. return a>b? a:b;
  15. }
  16. inline int gcd(int a,int b){
  17. return b==0? a:gcd(b,a%b);
  18. }
  19. signed main(){
  20. p[1]=mu[1]=1;
  21. for(int i=2;i<maxn;i++){
  22. if(p[i]==0)
  23. lst[++cnt]=i,mu[i]=-1;
  24. for(int j=1;j<=cnt;j++){
  25. if(i*lst[j]>=maxn)
  26. break;
  27. p[i*lst[j]]=1;
  28. if(i%lst[j]==0){
  29. mu[i*lst[j]]=0;
  30. break;
  31. }
  32. mu[i*lst[j]]=-mu[i];
  33. }
  34. }
  35. for(int i=1;i<maxn;i++)
  36. if(mu[i]!=0)
  37. ok[++tot]=i,ord[i]=tot;
  38. for(int i=1;i<maxn;i++){
  39. for(int j=1;i*j<maxn;j++)
  40. d[i*j]++;
  41. f[i]=(f[i-1]+d[i])%mod;
  42. }
  43. scanf("%lld%lld%lld",&a,&b,&c);
  44. mn=min(min(a,b),c),mx=max(max(a,b),c);
  45. e=ans=0;
  46. for(int i=1;i<=tot;i++){
  47. if(ok[i]>mx)
  48. break;
  49. for(int j=1;j<=tot;j++){
  50. if(ok[i]*ok[j]>mx)
  51. break;
  52. if(mu[ok[i]*ok[j]]==0)
  53. continue;
  54. for(int k=j+1;k<=tot;k++){
  55. if(ok[i]*ok[j]*ok[k]>mx)
  56. break;
  57. if(mu[ok[i]*ok[k]]==0||gcd(ok[j],ok[k])>1)
  58. continue;
  59. from[++e]=ord[ok[i]*ok[j]],to[e]=ord[ok[i]*ok[k]],lcm[e]=ok[i]*ok[j]*ok[k];
  60. deg[from[e]]++,deg[to[e]]++;
  61. }
  62. }
  63. }
  64. for(int i=1;i<=tot;i++){
  65. if(ok[i]>mn)
  66. break;
  67. ans+=mu[ok[i]]*mu[ok[i]]*mu[ok[i]]*f[a/ok[i]]*f[b/ok[i]]*f[c/ok[i]];
  68. }
  69. for(int i=1;i<=e;i++){
  70. v[from[i]].push_back(to[i]),w[from[i]].push_back(lcm[i]);
  71. v[to[i]].push_back(from[i]),w[to[i]].push_back(lcm[i]);
  72. }
  73. for(int i=1;i<=tot;i++){
  74. if(ok[i]>min(a,b))
  75. break;
  76. for(int j=0;j<v[i].size();j++){
  77. int x=ok[i],y=ok[v[i][j]],z=w[i][j];
  78. ans=(ans+mu[x]*mu[y]*mu[y]*f[a/z]*f[b/z]*f[c/y]%mod+mod)%mod;
  79. ans=(ans+mu[x]*mu[x]*mu[y]*f[a/x]*f[b/z]*f[c/z]%mod+mod)%mod;
  80. ans=(ans+mu[x]*mu[x]*mu[y]*f[a/z]*f[b/x]*f[c/z]%mod+mod)%mod;
  81. }
  82. }
  83. memset(v,0,sizeof(v));
  84. memset(w,0,sizeof(w));
  85. for(int i=1;i<=e;i++){
  86. if(deg[from[i]]>=deg[to[i]])
  87. v[from[i]].push_back(to[i]),w[from[i]].push_back(lcm[i]);
  88. else v[to[i]].push_back(from[i]),w[to[i]].push_back(lcm[i]);
  89. }
  90. for(int i=1;i<=tot;i++){
  91. if(ok[i]>mx)
  92. break;
  93. for(int j=0;j<v[i].size();j++)
  94. mrk[v[i][j]]=w[i][j];
  95. for(int j=0;j<v[i].size();j++){
  96. int x=v[i][j];
  97. for(int k=0;k<v[x].size();k++){
  98. int y=v[x][k],p=mrk[y],q=w[i][j],r=w[x][k];
  99. if(mrk[y]==0)
  100. continue;
  101. int st1,st2,st3,st4,st5,st6;
  102. st1=f[a/p]*f[b/q]*f[c/r]%mod;
  103. st2=f[a/p]*f[b/r]*f[c/q]%mod;
  104. st3=f[a/q]*f[b/p]*f[c/r]%mod;
  105. st4=f[a/q]*f[b/r]*f[c/p]%mod;
  106. st5=f[a/r]*f[b/p]*f[c/q]%mod;
  107. st6=f[a/r]*f[b/q]*f[c/p]%mod;
  108. ans=(ans+mu[ok[i]]*mu[ok[x]]*mu[ok[y]]*(st1+st2+st3+st4+st5+st6)%mod+mod)%mod;
  109. }
  110. }
  111. for(int j=0;j<v[i].size();j++)
  112. mrk[v[i][j]]=0;
  113. }
  114. printf("%lld\n",(ans+mod)%mod);
  115. return 0;
  116. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注