http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1244

模板题。。。

杜教筛和基于质因子分解的筛法都写了一下模板。


杜教筛

用杜教筛求积性函数\(f(n)\)的前缀和\(S(n)=\sum\limits_{i=1}^nf(i)\),需要构造一个\(g(n)\)使得\(\sum\limits_{d|n}f(d)g\left(\frac nd\right)\)和\(\sum\limits_{i=1}^ng(i)\)都可以快速求出。因为我们有公式:

\[\sum_{i=1}^n\sum_{d|i}f(d)g\left(\frac id\right)=\sum_{i=1}^ng(i)S\left(\left\lfloor\frac ni\right\rfloor\right)
\]

对于\(\mu(n)\)的前缀和,很明显\(g(n)=1\)。这样的话:

\[\sum_{i=1}^n\sum_{d|i}\mu(d)=1=\sum_{i=1}^nS\left(\left\lfloor\frac ni\right\rfloor\right)
\]

\[S(n)=1-\sum_{i=2}^nS\left(\left\lfloor\frac ni\right\rfloor\right)
\]

用Hash表存储S的值

  1. #include<cmath>
  2. #include<cstdio>
  3. #include<cstring>
  4. #include<algorithm>
  5. using namespace std;
  6. typedef long long ll;
  7. const ll N = 1E10;
  8. const int UP = 3981071;
  9. int mu[UP + 3], prime[UP + 3], num = 0, sum[UP + 3];
  10. bool notp[UP + 3];
  11. void Euler_shai() {
  12. sum[1] = 1;
  13. for (int i = 2; i <= UP; ++i) {
  14. if (!notp[i]) {
  15. prime[++num] = i;
  16. mu[i] = -1;
  17. }
  18. for (int j = 1, pro; j <= num && (pro = prime[j] * i) <= UP; ++j) {
  19. notp[pro] = true;
  20. if (i % prime[j] == 0) {
  21. mu[pro] = 0;
  22. break;
  23. } else
  24. mu[pro] = -mu[i];
  25. }
  26. sum[i] = sum[i - 1] + mu[i];
  27. }
  28. }
  29. struct HashTable {
  30. static const int p = 1000007;
  31. ll val[p], ref[p];
  32. HashTable() {memset(ref, -1, sizeof(ref));}
  33. void add(ll pos, ll nu) {
  34. int tmp = (int) (pos % p);
  35. while (ref[tmp] != -1) {
  36. if (ref[tmp] == pos) return;
  37. ++tmp; if (tmp == p) tmp = 0;
  38. }
  39. ref[tmp] = pos;
  40. val[tmp] = nu;
  41. }
  42. ll query(ll pos) {
  43. int tmp = (int) (pos % p);
  44. while (ref[tmp] != pos) {++tmp; if (tmp == p) tmp = 0;}
  45. return val[tmp];
  46. }
  47. } HT;
  48. ll Sum(ll x) {
  49. return x <= UP ? sum[x] : HT.query(x);
  50. }
  51. void DJ_shai(ll n) {
  52. for (ll i = n, y; i >= 1; i = n / (y + 1)) {
  53. y = n / i;
  54. if (y <= UP) continue;
  55. ll ret = 0;
  56. for (ll j = 2, l, pre = 1; j <= y; ++j) {
  57. l = y / j;
  58. j = y / l;
  59. ret += Sum(l) * (j - pre);
  60. pre = j;
  61. }
  62. HT.add(y, 1ll - ret);
  63. }
  64. }
  65. int main() {
  66. Euler_shai();
  67. ll a, b;
  68. scanf("%lld%lld", &a, &b);
  69. DJ_shai(b);
  70. DJ_shai(a - 1);
  71. printf("%lld\n", Sum(b) - Sum(a - 1));
  72. return 0;
  73. }

基于质因子分解的筛法

基于质因子分解的筛法细节比较多(貌似被称作洲哥筛?)。

\[\sum_{i=1}^n\mu(i)=\sum_{x\leq n且x无大于\sqrt n质因子}\mu(x)\left(1+\sum_{\sqrt n<p\leq\left\lfloor\frac nx\right\rfloor且p为质数}\mu(p)\right)
\]

设小于等于\(\sqrt n\)的质数从小到大排列为\(p_1,p_2\dots p_m\)。

设\(g(i,j)\)表示\([1,j]\)内与前i个质数互质的数的个数。

转移:\(g(i,j)=g(i-1,j)-g\left(i-1,\left\lfloor\frac j{p_i}\right\rfloor\right)\)

\(g(m,j)-1\)即为\([1,j]\)内大于\(\sqrt n\)的质数个数,它的相反数就是\(\sum\limits_{\sqrt n<p\leq j且p为质数}\mu(p)\)

枚举小于\(\sqrt n\)的所有数的\(\mu\),并和上面等式右边的括号内的数相乘求和。

这样剩下的就是大于等于\(\sqrt n\)的满足条件的\(\mu\)值,这些\(\mu\)值也要乘上括号内的数,不过这些括号内的数都是1,所以大于等于\(\sqrt n\)的满足条件的\(\mu\)值就可以统一计算了。

把\(p_1,p_2\dots p_m\)翻转,变成从大到小。

再设\(f(i,j)\)表示用前i个质数构成质因子的数中在\([1,j]\)内的数的\(\mu\)值和。

转移:\(f(i,j)=f(i-1,j)+\mu(p_i)f\left(i-1,\left\lfloor\frac j{p_i}\right\rfloor\right)\)

\(f(m,n)-\sum\limits_{1\leq i<\sqrt n}\mu(i)\)就是统一计算出来的和。

因为下取整只有\(O(\sqrt n)\)种取值,枚举小于等于\(\sqrt n\)的质数,质数个数大概是\(\frac{\sqrt n}{\log\sqrt n}\),所以时间复杂度是\(O\left(\frac n{\log n}\right)\)。

加上一些优化就可以达到\(O\left(\frac{n^{\frac 34}}{\log n}\right)\)。

这只是筛最简单的\(\mu\)的前缀和,更一般的积性函数的前缀和求法以及优化到\(O\left(\frac{n^{\frac 34}}{\log n}\right)\)的方法详见2016年候选人论文《积性函数求和的几种方法》,这里实在说不下了。

  1. #include<cmath>
  2. #include<cstdio>
  3. #include<cstring>
  4. #include<algorithm>
  5. using namespace std;
  6. typedef long long ll;
  7. const int N = 1E10;
  8. const int UP = 1E5;
  9. bool notp[UP + 3];
  10. int prime[UP + 3], sum_p[UP + 3], sum_mu[UP + 3], mu[UP + 3], pre[UP * 2 + 3], num = 0;
  11. ll G[UP * 2 + 3], F[UP * 2 + 3], J[UP * 2 + 3];
  12. void Euler_shai(int n) {
  13. mu[1] = sum_mu[1] = 1;
  14. for (int i = 2; i <= n; ++i) {
  15. if (!notp[i]) {
  16. prime[++num] = i;
  17. mu[i] = -1;
  18. sum_p[i] = sum_p[i - 1] + 1;
  19. } else
  20. sum_p[i] = sum_p[i - 1];
  21. for (int j = 1, pro; j <= num && (pro = i * prime[j]) <= n; ++j) {
  22. notp[pro] = true;
  23. if (i % prime[j] == 0) break;
  24. else mu[pro] = -mu[i];
  25. }
  26. sum_mu[i] = sum_mu[i - 1] + mu[i];
  27. }
  28. }
  29. struct HashTable {
  30. static const int ppp = 2333333;
  31. ll ref[ppp]; int val[ppp];
  32. void clr() {memset(ref, -1, sizeof(ref)); ref[0] = val[0] = 0;}
  33. void add(ll pos, int nu) {
  34. int tmp = pos % ppp;
  35. while (ref[tmp] != -1) {++tmp; if (tmp == ppp) tmp = 0;}
  36. ref[tmp] = pos; val[tmp] = nu;
  37. }
  38. int query(ll pos) {
  39. int tmp = pos % ppp;
  40. while (ref[tmp] != pos) {++tmp; if (tmp == ppp) tmp = 0;}
  41. return val[tmp];
  42. }
  43. } HT;
  44. ll ZY_shai(ll n) {
  45. int cnt = 0, sqf = floor(sqrt(n)), sqc = ceil(sqrt(n));
  46. while (prime[num] > sqf) --num;
  47. HT.clr();
  48. for (ll i = n, y; i >= 1; i = n / (y + 1)) {
  49. J[++cnt] = (y = n / i);
  50. HT.add(y, cnt);
  51. G[cnt] = y;
  52. pre[cnt] = 0;
  53. }
  54. ll pp, delta;
  55. for (int i = 1, p = prime[i]; i <= num; p = prime[++i]) {
  56. pp = 1ll * p * p;
  57. for (int j = cnt; j >= 1 && J[j] >= pp; --j) {
  58. int id = HT.query(J[j] / p);
  59. delta = max(G[id] - (i - 1 - pre[id]), 1ll);
  60. G[j] -= delta;
  61. pre[j] = i;
  62. }
  63. }
  64. for (int j = cnt; j >= 1; --j)
  65. G[j] = max(G[j] - (num - pre[j]), 1ll);
  66. ll ans = 0;
  67. for (int i = 1; i < sqc; ++i)
  68. ans += (2ll - G[HT.query(n / i)]) * mu[i];
  69. ll prep = 0;
  70. for (int j = 1; j <= cnt; ++j) F[j] = 1;
  71. for (int i = num, p = prime[i]; i >= 1; p = prime[--i]) {
  72. pp = 1ll * p * p;
  73. for (int j = cnt; j >= 1 && J[j] >= pp; --j) {
  74. if (J[j] < prep * prep) {
  75. if (J[j] > prep) F[j] = 1 - (sum_p[min(J[j], 1ll * sqf)] - sum_p[prep - 1]);
  76. else F[j] = 1;
  77. }
  78. int id = HT.query(J[j] / p);
  79. if (J[id] < prep * prep) {
  80. if (J[id] >= prep) delta = 1 - (sum_p[min(J[id], 1ll * sqf)] - sum_p[prep - 1]);
  81. else delta = 1;
  82. } else
  83. delta = F[id];
  84. F[j] -= delta;
  85. }
  86. prep = p;
  87. }
  88. return ans + F[cnt] - sum_mu[sqc - 1];
  89. }
  90. int main() {
  91. ll a, b;
  92. scanf("%lld%lld", &a, &b);
  93. Euler_shai((int) sqrt(b));
  94. b = ZY_shai(b);
  95. a = ZY_shai(a - 1);
  96. printf("%lld\n", b - a);
  97. return 0;
  98. }

总结

杜教筛比质因子分解筛法要快。质因子分解筛法可以筛更加一般的积性函数,比杜教筛无脑,但细节巨多,代码量大(容易写残)。

总算写完了

【51Nod 1244】莫比乌斯函数之和的更多相关文章

  1. 51nod 1244 莫比乌斯函数之和

    题目链接:51nod 1244 莫比乌斯函数之和 题解参考syh学长的博客:http://www.cnblogs.com/AOQNRMGYXLMV/p/4932537.html %%% 关于这一类求积 ...

  2. 51nod 1244 莫比乌斯函数之和 【杜教筛】

    51nod 1244 莫比乌斯函数之和 莫比乌斯函数,由德国数学家和天文学家莫比乌斯提出.梅滕斯(Mertens)首先使用μ(n)(miu(n))作为莫比乌斯函数的记号.具体定义如下: 如果一个数包含 ...

  3. [51Nod 1244] - 莫比乌斯函数之和 & [51Nod 1239] - 欧拉函数之和 (杜教筛板题)

    [51Nod 1244] - 莫比乌斯函数之和 求∑i=1Nμ(i)\sum_{i=1}^Nμ(i)∑i=1N​μ(i) 开推 ∑d∣nμ(d)=[n==1]\sum_{d|n}\mu(d)=[n== ...

  4. 51nod 1244 莫比乌斯函数之和(杜教筛)

    [题目链接] http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1244 [题目大意] 计算莫比乌斯函数的区段和 [题解] 利 ...

  5. 51Nod.1244.莫比乌斯函数之和(杜教筛)

    题目链接 map: //杜教筛 #include<map> #include<cstdio> typedef long long LL; const int N=5e6; in ...

  6. 51nod 1244 莫比乌斯函数之和 【莫比乌斯函数+杜教筛】

    和bzoj 3944比较像,但是时间卡的更死 设\( f(n)=\sum_{d|n}\mu(d) g(n)=\sum_{i=1}^{n}f(i) s(n)=\sum_{i=1}^{n}\mu(i) \ ...

  7. 51 NOD 1244 莫比乌斯函数之和(杜教筛)

    1244 莫比乌斯函数之和 基准时间限制:3 秒 空间限制:131072 KB 分值: 320 难度:7级算法题 收藏 关注 莫比乌斯函数,由德国数学家和天文学家莫比乌斯提出.梅滕斯(Mertens) ...

  8. 【51nod】1244 莫比乌斯函数之和

    题解 求积性函数的前缀和?杜教筛! 这不给一发杜教筛入门必备之博客= = https://blog.csdn.net/skywalkert/article/details/50500009 好了,然后 ...

  9. 51nod1244 莫比乌斯函数之和

    推公式.f[n]=1-∑f[n/i](i=2...n).然后递归+记忆化搜索.yyl说这叫杜教筛?时间复杂度貌似是O(n 2/3)的? #include<cstdio> #include& ...

  10. 51nod 1240 莫比乌斯函数

    题目链接:51nod 1240 莫比乌斯函数 莫比乌斯函数学习参考博客:http://www.cnblogs.com/Milkor/p/4464515.html #include<cstdio& ...

随机推荐

  1. 分布式系统理论进阶 - Paxos

    引言 <分布式系统理论基础 - 一致性.2PC和3PC>一文介绍了一致性.达成一致性需要面临的各种问题以及2PC.3PC模型,Paxos协议在节点宕机恢复.消息无序或丢失.网络分化的场景下 ...

  2. wordpress插件bug排查后记(记一次由于开启memecached引起的插件bug)

    这篇文章是写给自己的. 周三的时候我在维护公司的一个wordpress项目页面时发现了一个非常奇怪的情况:当我尝试更新网站上的一个页面后,在wordpress后台的编辑器中发现其内容并没有按我预期的将 ...

  3. 从N个元素的集合中随机取m个元素的算法实现

    最近有一个需求,比较简单,就是如标题所说的,从N个元素中随机取m个元素,当然这m个元素是不能存在重复的.本以为这么简单的需求,应该有现成的工具类来实现,但是几次查找居然没找到(有知道的可以推荐下哈^_ ...

  4. centos7查看系统版本,查看机器位数x86-64

    前言 由于不经常使用linux,每当使用的时候就是安装软件,安装软件的时候就要选择安装包平台,是32位的还是64位的.这时候突然发现不知道怎么查,于是百度.虽然轻而易举百度出来,但仍旧没有自己的笔记看 ...

  5. Java正则速成秘籍(三)之见招拆招篇

    导读 正则表达式是什么?有什么用? 正则表达式(Regular Expression)是一种文本规则,可以用来校验.查找.替换与规则匹配的文本. 又爱又恨的正则 正则表达式是一个强大的文本匹配工具,但 ...

  6. <input type="file">上传文件并添加路径到数据库

    注:这里是用的mvc所以没法用控件 html代码 <form method="post" enctype="multipart/form-data"> ...

  7. LeetCode Online Judge 1. Two Sum

    刷个题,击败0.17%... Given an array of integers, return indices of the two numbers such that they add up t ...

  8. java动态代理的2种实现方式

    java的动态代理在接java的api上有说明,这里就不写了.我理解的代理: 对特定接口中特定方法的功能进行扩展,这就是代理.代理是通过代理实例关联的调用处理程序对象调用方法. 下面通过一个例子看一下 ...

  9. 你搞懂 ORACLE、 SQLSERVER、MYSQL与DB2的区别了吗

    ORACLE. SQLSERVER.MYSQL与DB2的区别--平台性:    Oracle.MYSQL与DB2可在所有主流平台上运行:    SQL Server只能在Windows下运行: --安 ...

  10. MSSQL远程连接

    背景:部署公司自己研发的ERP系统. 1)系统架构: .NET+MSSQL. 2)服务器系统:Windows Server 2008 R2 Enterprise 3)数据库:MSSQL Server ...