数论+图论,妙不可言


# 题面

给定 \(A,B,C\),求:

\[\sum_{i=1}^A\sum_{j=1}^B\sum_{k=1}^C\sigma_0(ijk)
\]

数据规模:\(A,B,C\le 2\times10^5\)。


# 解析

显然 \(A,B,C\) 三者等价,不妨设 \(A\) 是最大的

关于 \(\sigma_0\),有一个众所周知(比如我就不知道) 的结论:

\[\sigma_0(ab)=\sum_{i\mid a}\sum_{j\mid b}[i\bot j]
\]

三个数也是一样的,

\[\sigma_0(abc)=\sum_{i\mid a}\sum_{j\mid b}\sum_{k\mid c}[i\bot j][j\bot k][k\bot i]
\]

于是直接代回我们要求的式子:

\[\begin{aligned}
&\sum_{i=1}^A\sum_{j=1}^B\sum_{k=1}^C\sum_{u\mid i}\sum_{v\mid j}\sum_{w\mid k}[u\bot v][v\bot w][w\bot u]\\
=&\sum_{u=1}^A\sum_{v=1}^B\sum_{w=1}^C[u\bot v][v\bot w][w\bot u]\left\lfloor\frac{A}{u}\right\rfloor\left\lfloor\frac{B}{v}\right\rfloor\left\lfloor\frac{C}{w}\right\rfloor
\end{aligned}
\]

记 \([a,b]\) 为 \(a, b\) 的最小公倍数。两数互质的条件可以进行反演:

\[\begin{aligned}
\sum_{a}\sum_{b}\sum_{c}\mu(a)\mu(b)\mu(c)\sum_{[a,b]\mid u}\left\lfloor\frac{A}{u}\right\rfloor\sum_{[b,c]\mid v}\left\lfloor\frac{B}{v}\right\rfloor\sum_{[c,a]\mid w}\left\lfloor\frac{C}{w}\right\rfloor
\end{aligned}
\]

定义 \(f_b(a)\) 如下:

\[f_b(a)=\sum_{a\mid i}\left\lfloor\frac{b}{i}\right\rfloor
\]

可以 \(O(A\ln A)\) 预处理出 \(f_A(x), f_B(x), f_C(x)\),于是要求的答案就是

\[\sum_{a}\sum_{b}\sum_{c}\mu(a)\mu(b)\mu(c)f_A([a,b])f_B([b,c])f_C([c,a])
\]

但是我们发现这一波推导过后并没有什么用,直接算还是 \(O(A^3)\) 的。只是可以进行一些剪枝?

  • \(\mu(a),\mu(b),\mu(c)\) 都必须非零,这样可以去掉很多无用的枚举;
  • \(\max\big\{[a,b],[b,c],[c,a]\big\}\le A\),好像也可以减掉一些枚举。

这些剪枝足够吗?如果仍然三重 for 循环枚举,这样剪枝过后还是过不了。但是注意到这两个限制,第二个限制与两个变量相关,类似于图上的边

  • 条件一限制了图上的点的 \(\mu\) 非零;
  • 条件二表示,若 \([a,b]\le A\),则图上存在 \((A,B)\) 这条无向边。

恰巧的是,我们计算的是一个三元组,体现在图上就是一个三元环

记 \(M\) 为图的边数,我们可以用下面的方法 \(O(M\sqrt{M})\) 地枚举所有三元环:

  • 统计每个点的度数,记作 \(deg_u\);
  • 给边定向,由度数大的点指向度数小的,若度数相等,则编号大的指向编号小的(编号小指向编号大也无所谓,反正要求二元组 \((\deg_u,u)\) 的大小比较唯一且具有传递性);
  • 枚举点 \(u\):
    • 标记 \(u\) 连出的所有点 \(v\);
    • 枚举 \(u\) 连出的点 \(v\):
      • 枚举 \(v\) 连出的点 \(w\),若 \(w\) 有标记,则找到三元环。

三元环计数正确性、时间复杂度的证明

根据边定向的规则,因为数对 $(deg_u, u)$ 的大小关系具有传递性且唯一确定,所以定向后的图一定是 DAG。

这意味着三元环一定是由 $u\to v\to w$ 和 $u\to w$ 构成的。且根据我们的枚举方式,这样的三元环仅能在枚举 $u$ 时计算到。所以计数不重不漏,正确性有保证。

时间复杂度的证明类似分块。首先,标记点的时间复杂度为 $O(M)$,因为每条边只会遍历一次,不是复杂度的瓶颈。

然后关注枚举的 $u\to v\to w$ 的中心点 $v$:

  • 若 $deg_v\le\sqrt{M}$,则 $w$ 只有 $O(\sqrt{M})$ 个,$(u,v)$ 最多 $O(M)$ 个,则所有此类点 $v$ 的复杂度为 $O(M\sqrt{M})$;
  • 若 $deg_v\gt\sqrt{M}$,因为 $u$ 连向 $v$,则 $deg_u\ge deg_v\gt\sqrt{M}$,这样的 $u$ 只有 $O(\sqrt{M})$ 个,而 $(v,w)$ 仅有 $O(M)$ 个;则所有此类 $v$ 点的复杂度也为 $O(M\sqrt{M})$。

总复杂度 $O(M\sqrt{M})$。

回到这道题上来,我们就是要枚举图上的一个三元环然后计算答案。那么这个图的边数多大呢?打个表发现 \(O(M\sqrt{M})\) 能过……(反正我不会证)

于是按上述方法枚举即可。

注意实际上枚举的不止有三元环,还存在 \(a=b\) 甚至是 \(a=b=c\) 的情况,不过这两种都可以直接暴力枚举,不是很重要。


# 源代码

/*Lucky_Glass*/
#include <vector>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std; #define con(typ) const typ &
typedef long long llong;
typedef pair<int, int> pii; inline int rin(int &r) {
int b = 1, c = getchar(); r = 0;
while ( c < '0' || '9' < c ) b = c == '-' ? -1 : b, c = getchar();
while ( '0' <= c && c <= '9' ) r = (r * 10) + (c ^ '0'), c = getchar();
return r *= b;
}
inline void write(con(int) w) {
if ( w > 9 ) write(w / 10), putchar((w % 10) ^ '0');
else if ( w < 0 ) putchar('-'), write(-w);
else putchar(w ^ '0');
} const int N = 2e5 + 10, M = 2e6, MOD = 1e9 + 7; inline int iGCD(con(int) a, con(int) b) {return b ? iGCD(b, a % b) : a;} int na, nb, nc, ncas, nprm, nedg;
int mu[N], prm[N], deg[N], edg[M][3], tag[N];
llong fa[N], fb[N], fc[N];
bool vis[N];
vector<pii> lnk[N]; void init() {
mu[1] = 1;
for (int i = 2; i < N; i++) {
if ( !vis[i] ) prm[++nprm] = i, mu[i] = -1;
for (int j = 1; j <= nprm && prm[j] * i < N; j++) {
vis[i * prm[j]] = true;
if ( i % prm[j] == 0 ) break;
mu[i * prm[j]] = -mu[i];
}
}
}
void proc(con(int) n, llong *arrf) {
for (int i = 1; i <= n; i++) {
arrf[i] = 0;
for (int j = i; j <= n; j += i)
arrf[i] += n / j;
}
}
int main() {
init();
rin(ncas);
while ( ncas-- ) {
rin(na), rin(nb), rin(nc);
int mx = max(na, max(nb, nc)), mn = min(na, min(nb, nc));
fill(fa, fa + mx + 1, 0);
fill(fb, fb + mx + 1, 0);
fill(fc, fc + mx + 1, 0);
proc(na, fa), proc(nb, fb), proc(nc, fc);
llong ans = 0;
// Part 1
for (int i = 1; i <= mn; i++)
ans += mu[i] * fa[i] * fb[i] * fc[i]; // mu[i] ^ 3 = mu[i]
// Part 2
fill(deg, deg + 1 + mx, 0), nedg = 0;
for (int g = 1; g <= mx; g++)
for (int i = 1; i * g <= mx; i++) if ( mu[i * g] )
for (int j = i + 1; 1ll * i * j * g <= mx; j++)
if ( mu[j * g] && iGCD(i, j) == 1 ) {
int lcm = i * j * g, ig = i * g, jg = j * g;
// iij
ans += mu[jg] * (fa[ig] * fb[lcm] * fc[lcm]
+ fa[lcm] * fb[ig] * fc[lcm]
+ fa[lcm] * fb[lcm] * fc[ig]);
// ijj
ans += mu[ig] * (fa[jg] * fb[lcm] * fc[lcm]
+ fa[lcm] * fb[jg] * fc[lcm]
+ fa[lcm] * fb[lcm] * fc[jg]);
// add edges at the same time :)
deg[ig]++, deg[jg]++;
edg[++nedg][0] = ig, edg[nedg][1] = jg;
edg[nedg][2] = lcm;
}
// Part 3
for (int i = 1; i <= mx; i++) lnk[i].clear();
for (int i = 1; i <= nedg; i++)
if ( deg[edg[i][0]] > deg[edg[i][1]]
|| (deg[edg[i][0]] == deg[edg[i][1]] && edg[i][0] < edg[i][1]) )
lnk[edg[i][0]].push_back(make_pair(edg[i][1], edg[i][2]));
else lnk[edg[i][1]].push_back(make_pair(edg[i][0], edg[i][2]));
for (int u = 1; u <= mx; u++) if ( mu[u] ) {
for (int i = 0, ii = (int)lnk[u].size(); i < ii; i++)
tag[lnk[u][i].first] = lnk[u][i].second;
for (int i = 0, ii = (int)lnk[u].size(); i < ii; i++) {
int v = lnk[u][i].first, luv = lnk[u][i].second;
for (int j = 0, _j = (int)lnk[v].size(); j < _j; j++)
if ( tag[lnk[v][j].first] ) {
int w = lnk[v][j].first, lvw = lnk[v][j].second,
luw = tag[w];
ans += mu[u] * mu[v] * mu[w] * (
fa[luv] * fb[luw] * fc[lvw]
+ fa[luv] * fb[lvw] * fc[luw]
+ fa[luw] * fb[luv] * fc[lvw]
+ fa[luw] * fb[lvw] * fc[luv]
+ fa[lvw] * fb[luv] * fc[luw]
+ fa[lvw] * fb[luw] * fc[luv]
);
}
}
for (int i = 0, ii = (int)lnk[u].size(); i < ii; i++)
tag[lnk[u][i].first] = 0;
}
write(int(ans % MOD)), putchar('\n');
}
return 0;
}

THE END

Thanks for reading!

怎知晓 有人 玩世不恭掩愁肠

取次花丛懒望 等剪烛西窗

怎知晓 有人 独为异客在异乡

嘴上逞强终不敢 举头看月光

——《从前有个衔玉教》By 星葵/鲜洋芋/溱绫西陌

> Link 【0412乐正绫诞生祭】从前有个衔玉教-Bilibili

「SOL」旧试题 (LOJ/SDOI)的更多相关文章

  1. loj#2565. 「SDOI2018」旧试题(反演 三元环计数)

    题意 题目链接 Sol 神仙反演题.在洛谷上疯狂被卡常 Orz shadowice #include<bits/stdc++.h> #define Pair pair<int, in ...

  2. LOJ2476. 「2018 集训队互测 Day 3」蒜头的奖杯 & LOJ2565. 「SDOI2018」旧试题(莫比乌斯反演)

    题目链接 LOJ2476:https://loj.ac/problem/2476 LOJ2565:https://loj.ac/problem/2565 题解 参考照搬了 wxh 的博客. 为了方便, ...

  3. [LOJ#6437][BZOJ5373]「PKUSC2018」PKUSC

    [LOJ#6437][BZOJ5373]「PKUSC2018」PKUSC 试题描述 九条可怜是一个爱玩游戏的女孩子. 最近她在玩一个无双割草类的游戏,平面上有 \(n\) 个敌人,每一个敌人的坐标为 ...

  4. 「NOI2018」归程

    「NOI2018」归程 题目描述 本题的故事发生在魔力之都,在这里我们将为你介绍一些必要的设定. 魔力之都可以抽象成一个 >\(1\) 个节点. \(m\) 条边的无向连通图(节点的编号从 \( ...

  5. 2090. 「ZJOI2016」旅行者 分治,最短路

    2090. 「ZJOI2016」旅行者 链接 loj 思路 \((l,mid)(mid+1,r)\).考虑跨过mid的贡献. 假设选的中间那条线的点为gzy,贡献为\(dis(x,gzy)+dis(g ...

  6. 【LOJ】#3088. 「GXOI / GZOI2019」旧词

    LOJ#3088. 「GXOI / GZOI2019」旧词 不懂啊5e4感觉有点小 就是离线询问,在每个x上挂上y的询问 然后树剖,每个节点维护轻儿子中已经被加入的点的个数个数乘上\(dep[u]^{ ...

  7. Loj #2192. 「SHOI2014」概率充电器

    Loj #2192. 「SHOI2014」概率充电器 题目描述 著名的电子产品品牌 SHOI 刚刚发布了引领世界潮流的下一代电子产品--概率充电器: 「采用全新纳米级加工技术,实现元件与导线能否通电完 ...

  8. Loj #3096. 「SNOI2019」数论

    Loj #3096. 「SNOI2019」数论 题目描述 给出正整数 \(P, Q, T\),大小为 \(n\) 的整数集 \(A\) 和大小为 \(m\) 的整数集 \(B\),请你求出: \[ \ ...

  9. Loj #3093. 「BJOI2019」光线

    Loj #3093. 「BJOI2019」光线 题目描述 当一束光打到一层玻璃上时,有一定比例的光会穿过这层玻璃,一定比例的光会被反射回去,剩下的光被玻璃吸收. 设对于任意 \(x\),有 \(x\t ...

  10. Loj #3089. 「BJOI2019」奥术神杖

    Loj #3089. 「BJOI2019」奥术神杖 题目描述 Bezorath 大陆抵抗地灾军团入侵的战争进入了僵持的阶段,世世代代生活在 Bezorath 这片大陆的精灵们开始寻找远古时代诸神遗留的 ...

随机推荐

  1. Ubuntu下安装Node.js+ThreeJs

    以具有sudo特权的用户身份运行以下命令,以下载并执行NodeSource安装脚本 curl -sL https://deb.nodesource.com/setup_16.x | sudo -E b ...

  2. docker学习(dockerfile打jar包为镜像)

    docker打包jar为docker镜像 1.使用Dockerfile打镜像 将spring boot应用打包成jar包放置在/app/applcation路径中 编写dockerfile文件,内容参 ...

  3. springboot启动日志:Multiple Spring Data modules found, entering strict repository configuration mode

    问题描述 最近启动springboot项目的时候,发现有一条日志:Multiple Spring Data modules found, entering strict repository conf ...

  4. MySQL 学习(四)并集查询

    联合查询,它是用 union 关键字把多条 select 语句的查询结果合并为一个结果集.纵向合并的前提是被合并的结果集的字段数量.顺序和数据类型必须完全一致.字段名不一样的情况下,会将第一个结果集的 ...

  5. ROS-安装与开发速记

    参考教程: B站视频(感谢赵老师):https://www.bilibili.com/video/BV1Ci4y1L7ZZ?p=14&spm_id_from=pageDriver 课程文件:h ...

  6. vue 定时器 定时刷新页面 定时请求接口

    data(){ return{ intervalId:null, } }, methods:{ // 定时刷新数据函数 dataRefreh() { // 计时器正在进行中,退出函数 if (this ...

  7. chatgpt 的训练数据时间内容估计

    I noticed that the data you quoted is dated September 2021, but it's already 2023. I apologize for t ...

  8. 【阿里云ACP】-01(阿里云综述、弹性计算)

    课程能力 课程范围 ECS 磁盘 实例 磁盘 快照 镜像 网络 安全组 AS 伸缩组 伸缩配置 伸缩规则 伸缩活动 伸缩触发任务 伸缩模式 冷却时间 SLB 定义 实现原理 支持的协议 绘画保持 健康 ...

  9. onActivityResult 解耦 不需要一层一层的写

    public abstract class AbsShareMessageTemplates implements IShareMessageTemplates { public final stat ...

  10. QT如何安装?

    Qt安装教程 OLD HELPS <oldhelps@126.com > 目录 Qt安装教程 下载 注册.登录 接受验证邮件 安装 下载 从https://download.qt.io/n ...