题意

有一张 \(n\times m\) 的数表,其第\(i\)行第\(j\)列的数值为能同时整除\(i\)和\(j\)的所有自然数之和。

\(T\)组数据,询问对于给定的 \(n,m,a\) , 计算数表中\(\leq a\) 的数之和。

\(T \leq 2\times 10^4,1 \leq n,m\leq 10^5\).

题解

令\(\sigma(x)\)表示\(x\)的约数和,容易写出答案的式子:

\[\sum_{i=1}^n \sum_{j=1}^m\sigma(\gcd(i,j))[\sigma(\gcd(i,j))\leq a]
\]

然后使用常见套路变换式子:(下面默认\(n\leq m\))

\[=\sum_{d=1}^n \sigma(d)[\sigma(d)\leq a] \sum_{i=1}^n \sum_{j=1}^m[\gcd(i,j)=d]
\]

\[=\sum_{d=1}^n \sigma(d)[\sigma(d)\leq a] \sum_{i=1}^{\lfloor\frac{n}{d}\rfloor} \sum_{j=1}^{\lfloor\frac{m}{d}\rfloor}[\gcd(i,j)=1]
\]

\[=\sum_{d=1}^n \sigma(d)[\sigma(d)\leq a] \sum_{i=1}^{\lfloor\frac{n}{d}\rfloor} \sum_{j=1}^{\lfloor\frac{m}{d}\rfloor} \sum_{d'|i,d'j} \mu(d')
\]

\[=\sum_{d=1}^n \sigma(d)[\sigma(d)\leq a]\sum_{d'=1}^{\lfloor\frac{n}{d} \rfloor}\mu(d') \lfloor\frac{n}{dd'}\rfloor \lfloor\frac{m}{dd'}\rfloor
\]

我们记前面那部分\(f(d)=\sigma(d)[\sigma(d)\leq a]\):

\[=\sum_{i=1}^n f(d)\sum_{d'=1}^{\lfloor\frac{n}{d} \rfloor}\mu(d') \lfloor\frac{n}{dd'}\rfloor \lfloor\frac{m}{dd'}\rfloor
\]

枚举乘积\(k=dd'\):

\[=\sum_{k=1}^n\lfloor\frac{n}{k}\rfloor \lfloor\frac{m}{k}\rfloor\sum_{d|k}f(d)\mu(\frac{k}{d})
\]

可以发现后面变成了狄利克雷卷积的形式!

记$$g(k)=\sum_{d|k} f(d)\mu(\frac{k}{d})$$,即\(g=f*\mu\):

\[=\sum_{i=1}^n \lfloor \frac{n}{k} \rfloor \lfloor \frac{m}{k}\rfloor g(k)
\]

可以看出我们对于每个\(n,m\),可以数论分块

但是\(g(k)\)会随着\(a\)的变化而变化,不能每次计算一遍\(g\)

但是注意到,\(g\)变化是因为\(f\),\(f\)只有\(10^5\)种取值。

于是我们可以把询问离线后按\(a\)从小到大排序,每次加入一些满足\(\sigma(d)\leq a\)的\(d\)

然后考虑加入一个\(d\)有什么影响:使得所有\(d|k\)的\(g(k)\)加上\(f(d)\mu(\frac{k}{d})\)

就可以每次枚举\(d\)的倍数\(k\),然后更新\(g(k)\),最多更新\([1,n]\)这些数,根据调和级数可得枚举的总复杂度为\(O(n \log n)\)

别忘了数论分块是需要前缀和的,

所以现在我们需要一种支持快速单点加、求前缀和的数据结构,树状数组就很合适

然后就做完了,复杂度\(O(n \log^2 n+T\sqrt n \log n)\)

一个小细节:\(\sigma\)函数怎么线性筛?

考虑质因数分解后\(\sigma (x)=(1+p_1+p_1^2+..+p_1^{c_1})..(1+p_k+p_k^2+..+p_k^{c_k})\)

因此线性筛的时候记录一个\(tmp(x)\)表示\(1+p+p^2..+p^c\),其中\(p\)为\(x\)的最小质因子,\(c\)的\(p\)的指数;然后就可以做了

一个减小常数的小技巧:分块的时候记录一个变量,减少重复的询问,详见代码

  1. #include <algorithm>
  2. #include <cstdio>
  3. using namespace std;
  4. typedef long long ll;
  5. const int R = 1e5;
  6. const int N = 1e5 + 10;
  7. const int M = 2e4 + 10;
  8. const ll mo = 1ll << 31;
  9. struct qs {
  10. int n, m, a, id;
  11. bool operator < (const qs &b) const {
  12. return a < b.a;
  13. }
  14. } q[M];
  15. int t, tot, p[N], mu[N], sig[N], tmp[N], ans[M];
  16. bool tag[N];
  17. struct num {
  18. int x;
  19. bool operator < (const num &b) const {
  20. return sig[x] < sig[b.x];
  21. }
  22. } a[N];
  23. void sieve(int n) {
  24. sig[1] = mu[1] = 1;
  25. for(int i = 2; i <= n; i ++) {
  26. if(!tag[i]) {
  27. p[tot ++] = i; mu[i] = -1;
  28. sig[i] = tmp[i] = i + 1;
  29. }
  30. for(int j = 0; j < tot; j ++) {
  31. if(p[j] * i > n) break ;
  32. tag[i * p[j]] = 1;
  33. if(i % p[j] == 0) {
  34. mu[i * p[j]] = 0;
  35. tmp[i * p[j]] = tmp[i] * p[j] + 1;
  36. sig[i * p[j]] = sig[i] / tmp[i] * tmp[i * p[j]];
  37. break ;
  38. }
  39. mu[i * p[j]] = - mu[i];
  40. tmp[i * p[j]] = 1 + p[j];
  41. sig[i * p[j]] = sig[i] * (1 + p[j]);
  42. }
  43. }
  44. for(int i = 1; i <= n; i ++) a[i].x = i;
  45. sort(a + 1, a + n + 1);
  46. }
  47. int bit[N];
  48. void add(int x, int y) {
  49. for(; x <= R; x += x & (-x))
  50. bit[x] = ((ll) bit[x] + y) % mo;
  51. }
  52. int qry(int x) {
  53. int ans = 0;
  54. for(; x >= 1; x &= x - 1)
  55. ans = ((ll) ans + bit[x]) % mo;
  56. return ans;
  57. }
  58. void ins(int x) {
  59. for(int k = 1; x * k <= R; k ++)
  60. add(x * k, (ll) mu[k] * sig[x] % mo);
  61. }
  62. int query(int n, int m) {
  63. int ans = 0, la = 0, nw;
  64. for(int i = 1, j; i <= n; i = j + 1, la = nw) {
  65. j = min(n / (n / i), m / (m / i)); nw = qry(j);
  66. ans = (ans + ((ll) nw - la) % mo * (n / i) % mo * (m / i) % mo) % mo;
  67. }
  68. return ((ll)ans + mo) % mo;
  69. }
  70. int main() {
  71. sieve(R); scanf("%d", &t);
  72. for(int i = 1; i <= t; i ++) {
  73. scanf("%d%d%d", &q[i].n, &q[i].m, &q[i].a);
  74. if(q[i].n > q[i].m) swap(q[i].n, q[i].m);
  75. q[i].id = i;
  76. }
  77. sort(q + 1, q + t + 1);
  78. int j = 1;
  79. for(int i = 1; i <= t; i ++) {
  80. for(; j <= R && sig[a[j].x] <= q[i].a; j ++) ins(a[j].x);
  81. ans[q[i].id] = query(q[i].n, q[i].m);
  82. }
  83. for(int i = 1; i <= t; i ++)
  84. printf("%d\n", ans[i]);
  85. return 0;
  86. }

「BZOJ 3529」「SDOI 2014」数表「莫比乌斯反演」的更多相关文章

  1. 【BZOJ 3529】【SDOI 2014】数表

    看Yveh的题解,这道题卡了好长时间,一直不明白为什么要······算了当时太naive我现在都不好意思说了 #include<cstdio> #include<cstring> ...

  2. 「BZOJ 3994」「SDOI 2015」约数个数和「莫比乌斯反演」

    题意 设\(d(x)\)为\(x\)的约数个数,求\(\sum_{i=1}^{n}\sum_{j=1}^{m}d(ij)\). 题解 首先证个公式: \[d(ij) = \sum_{x|i}\sum_ ...

  3. ☆ [POI2007] ZAP-Queries 「莫比乌斯反演」

    题目类型:莫比乌斯反演 传送门:>Here< 题意:求有多少对正整数对\((a,b)\),满足\(0<a<A\),\(0<b<B\),\(gcd(a,b)=d\) ...

  4. 「CF235E」Number Challenge「莫比乌斯反演」

    一个结论:(从二维扩展来的,三维也是对的,证明可以考虑质因数分解) \[ d(ijk)=\sum_{i'|i}\sum_{j'|j}\sum_{k'|k}[\gcd(i',j')=1][\gcd(i' ...

  5. 【BZOJ 3531】【SDOI 2014】旅行

    因为有$10^5$个宗教,需要开$10^5$个线段树. 平时开的线段树是“满”二叉树,但在这个题中代表一个宗教的线段树管辖的区间有很多点都不属于这个宗教,也就不用“把枝叶伸到这个点上”,所以这样用类似 ...

  6. 【BZOJ 3530】【SDOI 2014】数数

    http://www.lydsy.com/JudgeOnline/problem.php?id=3530 上午gty的测试题,爆0了qwq 类似文本生成器那道题,把AC自动机的转移建出来,准确地说建出 ...

  7. bzoj 3529 [Sdoi2014]数表(莫比乌斯反演+BIT)

    Description 有一张N×m的数表,其第i行第j列(1 < =i < =礼,1 < =j < =m)的数值为能同时整除i和j的所有自然数之和.给定a,计算数表中不大于a ...

  8. 【SDOI 2014】数表

    题意 https://loj.ac/problem/2193 题解 ​显然就是求 $\sum\limits_{i=1}^{n} \sum\limits_{j=1}^{m} \sigma_1(\gcd{ ...

  9. BZOJ 2005 [Noi2010]能量采集 (数学+容斥 或 莫比乌斯反演)

    2005: [Noi2010]能量采集 Time Limit: 10 Sec  Memory Limit: 552 MBSubmit: 4493  Solved: 2695[Submit][Statu ...

随机推荐

  1. POJ2976(最大化平均值)

    Dropping tests Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 9329   Accepted: 3271 De ...

  2. (转)SqlDependency学习笔记

    本文转载自:http://www.cnblogs.com/yjmyzz/archive/2009/06/14/1502921.html sqlDependency提供了这样一种能力:当被监测的数据库中 ...

  3. String是基本的数据类型吗?

    String不是基本的数据类型,是final修饰的java类,java中的基本类型一共有8个,它们分别为: 1 字符类型:byte,char 2 基本整型:short,int,long 3 浮点型:f ...

  4. Python函数(一)-return返回值

    定义一个函数可以在最后加上return返回值,方便查看函数是否运行完成和返回函数的值 # -*- coding:utf-8 -*- __author__ = "MuT6 Sch01aR&qu ...

  5. CSS3新特性详解

    本文讲解CSS3相关实用知识点 CSS3相关实用知识点目录 边框设置 颜色设置 背景设置 渐变使用 超出文本设置 阴影设置 CSS3变换设置 过渡设置 动画设置 多列布局 BoxSizing设置 弹性 ...

  6. vue-cli脚手架build目录中的karma.conf.js配置文件

    本文系统讲解vue-cli脚手架build目录中的karma.conf.js配置文件 这个配置文件是命令 npm run unit 的入口配置文件,主要用于单元测试 这条命令的内容如下 "c ...

  7. 窗体的keypreview属性的作用是什么?(设置快捷键和钩子)

    如果把窗体的KeyPreview属性设为True,那么窗体将比其内的控件优先获得键盘事件的激活权.比如窗体Form1和其内的文本框Text1都准备响应KeyPress事件,那么以下代码将首先激活窗体的 ...

  8. apache server和tomcat集群配置三:水平集群下的tomcat集群配置

    在jsp文件中加入以下代码,用来测试是否共享session: SessionID: <%= session.getId() %> 之前尝试在linux中,但是因为模拟环境是虚拟机,虚拟机只 ...

  9. import gevent 协程 import greenlet

  10. android-auto-scroll-view-pager (无限广告轮播图)

    github 地址: https://github.com/Trinea/android-auto-scroll-view-pager Gradle: compile ('cn.trinea.andr ...