link

题意:求出\(\sum_{i=1}^n\sum_{j=1}^m\varphi(ij)\),对998244353取模

多组数据,\(T\le 10^4,n,m\le 10^5\)。

前置知识:\(\varphi(ij)=\frac{\varphi(i)\varphi(j)\gcd(i,j)}{\varphi(\gcd(i,j))}\)

证明:我是口胡呢还是好好证呢还是口胡吧

按照欧拉函数的计算式展开,会发现,左边是\(ij\prod_{p|i \mathrm{\color{green}{or}}p|j}\frac{p-1}p\)

右边是\(\frac{i\prod_{p|i}\frac{p-1}pj\prod_{p|j}\frac{p-1}p\gcd(i,j)}{\gcd(i,j)\prod_{p|i\mathrm{\color{green}{and}}p|j}\frac{p-1}p}\)

显然,根据容斥原理,两边是相等的

然后推式子

\(\sum_{i=1}^n\sum_{j=1}^m\varphi(ij)\)

\(=\sum_{i=1}^n\sum_{j=1}^m\frac{\varphi(i)\varphi(j)\gcd(i,j)}{\varphi(\gcd(ij))}\)

\(=\sum_{p=1}^n\frac p{\varphi(p)}\sum_{i=1}^n\sum_{j=1}^m\varphi(i)\varphi(j)[\gcd(i,j)=p]\)

\(=\sum_{p=1}^n\frac p{\varphi(p)}\sum_{i=1}^{n/p}\sum_{j=1}^{m/p}\varphi(ip)\varphi(jp)[\gcd(i,j)=1]\)

\(=\sum_{p=1}^n\frac p{\varphi(p)}\sum_{i=1}^{n/p}\sum_{j=1}^{m/p}\varphi(ip)\varphi(jp)\sum_{d|i,d|j}\mu(d)\)

\(=\sum_{p=1}^n\frac p{\varphi(p)}\sum_{d=1}^n\mu(d)\sum_{i=1}^{n/dp}\sum_{j=1}^{m/dp}\varphi(idp)\varphi(jdp)\)

\(=\sum_{q=1}^n\sum_{p|q}\frac{p\mu(\frac qp)}{\varphi(p)}\sum_{i=1}^{n/q}\sum_{j=1}^{m/q}\varphi(iq)\varphi(jq)\)

\(=\sum_{q=1}^n\left(\sum_{p|q}\frac{p\mu(\frac qp)}{\varphi(p)}\right)\left(\sum_{i=1}^{n/q}\varphi(iq)\right)\left(\sum_{i=1}^{m/q}\varphi(iq)\right)\)

前面这一部分好处理--\(O(n\log n)\)枚举倍数。后面?按照套路?数论分块?怎么分????

观察了你谷题解后,终于懂了

设\(sum(q)=\sum_{p|q}\frac{p\mu(\frac qp)}{\varphi(p)}\),显然可以在\(O(n\log n)\)的时间复杂度内处理出来。

设\(g(x,y)=\sum_{i=1}^x\varphi(iy)\),显然有递推式\(g(x,y)=g(x-1,y)+\varphi(xy)\)。

由于\(xy<=n\),对于每个\(x\),有\(\frac nx\)的数值,我们可以通过动态申请内存,在\(O(n\log n)\)的时间复杂度和空间复杂度内求出\(g\)数组。

设\(T(n,a,b)=\sum_{q=1}^n\left(\sum_{p|q}\frac{p\mu(\frac qp)}{\varphi(p)}\right)\left(\sum_{i=1}^{a}\varphi(iq)\right)\left(\sum_{i=1}^{b}\varphi(iq)\right)=\sum_{q=1}^nsum(q)g(a,q)g(b,q)\)

显然T的递推式为\(T(n,a,b)=T(n-1,a,b)+sum(n)g(a,n)g(b,n)\)

根据数论分块那套理论,对于一个\(n/q\)和\(m/q\)相同的\(q\)的区间,当\(n/q=a,m/q=b\)时,这一区间的\(ans=T(r,a,b)-T(l-1,a,b)\),r和l是这一区间内的最大值和最小值

我们考虑预处理\(n*B*B\)范围的答案,B是我们钦定的一个数字,T数组开的空间复杂度为\(O(nB^2)\)(实际上由于\(a*n,b*n\le 10^5\)的限制,应该开不到\(O(nB^2)\)。

对于每次询问,我们只能在\(n/q\le B\)时候进行数论分块操作通过\(T\)数组计算答案,复杂度根据数论分块那套理论为\(O(\sqrt n)\)。

对于\(n/q>B\)的部分,有\(q<n/B\),暴力枚举\(q\),通过\(g\)数组计算答案,这一部分单次计算的复杂度为\(O(n/B)\)。

总复杂度为\(O(n\log n+nB^2+T(\sqrt n+n/B))\)。实测,B开到50左右跑的快一点,且内存占用超小。

下面是乱七八糟的代码= =

注意讲文明,new来的内存要主动回收垃圾

注意取模(这题如果写的复杂度没错的话不卡常,开#define int long long也是没问题的

#include <cstdio>
#include <functional>
using namespace std; const int p = 998244353;
const int b = 50;
bool vis[100010];
int prime[100010], tot, fuck = 100000;
int mu[100010], phi[100010], invphi[100010];
int sum[100010];
int *g[100010], *t[100][100]; //注意这里t数组下标是[2][3][1] int qpow(int x, int y)
{
int res = 1;
for (x %= p; y > 0; x = x * (long long)x % p, y >>= 1) if (y & 1) res = res * (long long)x % p;
return res;
} int main()
{
//线性筛phi,mu,预处理前面的部分
phi[1] = mu[1] = invphi[1] = 1;
for (int i = 2; i <= fuck; i++)
{
if (vis[i] == false) prime[++tot] = i, phi[i] = i + (mu[i] = -1);
for (int j = 1; j <= tot && i * prime[j] <= fuck; j++)
{
vis[i * prime[j]] = true;
if (i % prime[j] == 0) { phi[i * prime[j]] = phi[i] * prime[j]; break; }
phi[i * prime[j]] = phi[i] * (prime[j] - 1);
mu[i * prime[j]] = -mu[i];
}
invphi[i] = qpow(phi[i], p - 2);
if (phi[i] * (long long)invphi[i] % p != 1) { return -233; printf("cnm\n"); }
}
for (int pp = 1; pp <= fuck; pp++)
for (int q = pp, d = 1; q <= fuck; q += pp, d++)
sum[q] = (sum[q] + pp * (long long)invphi[pp] % p * mu[d]) % p, sum[q] += (sum[q] < 0 ? p : 0); //处理g数组
for (int i = 1; i <= fuck; i++)
{
g[i] = new int[(fuck / i) + 1], g[i][0] = 0;
for (int j = 1, sb = fuck / i; j <= sb; j++)
g[i][j] = (g[i][j - 1] + phi[i * j]) % p;
} //处理t数组 注意有第一维<=第二维,因为下面我们强制n<=m了
for (int j = 1; j <= b; j++)
for (int k = j; k <= b; k++)
{
int len = fuck / max(j, k);
t[j][k] = new int[len + 1], t[j][k][0] = 0;
for (int i = 1; i <= len; i++)
t[j][k][i] = (t[j][k][i - 1] + sum[i] * (long long)g[i][j] % p * g[i][k] % p) % p;
} //处理询问
int tat;
scanf("%d", &tat);
while (tat --> 0)
{
int n, m, res = 0;
scanf("%d%d", &n, &m);
if (n > m) swap(n, m);
//对于n/q>b的部分,暴力,通过g数组和sum数组计算计算
for (int i = 1, sb = m / b; i <= sb; i++)
res = (res + sum[i] * (long long)g[i][n / i] % p * g[i][m / i] % p) % p;
//对于n/q<b的部分,数论分块,通过b数组计算
for (int i = m / b + 1, j; i <= n; i = j + 1)
{
j = min(n / (n / i), m / (m / i));
res = (res + t[n / i][m / i][j] - t[n / i][m / i][i - 1]) % p, res += (res < 0 ? p : 0);
}
printf("%d\n", res);
} //垃圾回收
for (int i = 1; i <= fuck; i++)
delete []g[i], g[i] = 0;
for (int i = 1; i <= b; i++)
for (int j = i; j <= b; j++)
delete[] t[i][j], t[i][j] = 0;
return 0;
}

luogu4240 毒瘤之神的考验(毒瘤乌斯反演)的更多相关文章

  1. 洛谷 P4240 毒瘤之神的考验 解题报告

    P4240 毒瘤之神的考验 题目背景 \(\tt{Salamander}\)的家门口是一条长长的公路. 又是一年春天将至,\(\tt{Salamander}\)发现路边长出了一排毒瘤! \(\tt{S ...

  2. P4240 毒瘤之神的考验

    题目 P4240 毒瘤之神的考验 神仙题\(emmm\) 前置 首先有一个很神奇的性质: \(\varphi(ij)=\dfrac{\varphi(i)\varphi(j)gcd(i,j)}{\var ...

  3. 洛谷 P4240 - 毒瘤之神的考验(数论+复杂度平衡)

    洛谷题面传送门 先扯些别的. 2021 年 7 月的某一天,我和 ycx 对话: tzc:你做过哪些名字里带"毒瘤"的题目,我做过一道名副其实的毒瘤题就叫毒瘤,是个虚树+dp yc ...

  4. [luogu 4240] 毒瘤之神的考验

    题目背景 Salamander的家门口是一条长长的公路. 又是一年春天将至,Salamander发现路边长出了一排毒瘤! Salamander想带一些毒瘤回家,但是,这时毒瘤当中钻出来了一个毒瘤之神! ...

  5. Luogu4240 毒瘤之神的考验 莫比乌斯反演、根号分治

    传送门 首先有\(\varphi(ij) = \frac{\varphi(i) \varphi(j) \gcd(i,j)}{\varphi(\gcd(i,j))}\),把欧拉函数的定义式代入即可证明 ...

  6. luogu 4240 毒瘤之神的考验 (莫比乌斯反演)

    题目大意:略 题面传送门 果然是一道神duliu题= = 出题人的题解传送门 出题人的题解还是讲得很明白的 1.关于$\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{m ...

  7. 洛谷P4240 毒瘤之神的考验 【莫比乌斯反演 + 分块打表】

    题目链接 洛谷P4240 题解 式子不难推,分块打表真的没想到 首先考虑如何拆开\(\varphi(ij)\) 考虑公式 \[\varphi(ij) = ij\prod\limits_{p | ij} ...

  8. Luogu 4240:毒瘤之神的考验

    传送门 Sol 分开考虑 \(\varphi(ij)\) 中 \(ij\) 的质因子 那么 \[\varphi(ij)=\frac{\varphi(i)\varphi(j)gcd(i,j)}{\var ...

  9. 从 [P4240 毒瘤之神的考验] 谈 OI 中的美学

    感觉这题真的特别有意思,涉及了 OI 中很多非常有意思.非常美的手法,比如--平衡两部分的时间复杂度.\(n \ln n\) 的那个 Trick等等,真的一种暴力的美学. 题目大意: 多组询问,求 \ ...

随机推荐

  1. JavaEE中的Cookie的基本使用方法

    之前一直使用的是统一登录系统,相关的登录由别的部门开发以及维护.但由于最近项目的需要,我们需要自己开发一套简单的登录功能.因此这里就涉及到了一个Cookie的功能.之前也了解过相关的内容,但这次需要独 ...

  2. IDA Pro权威指南学习笔记(一)

    一直不懂逆向,最近刚好不忙,于是学习逆向,用来做笔记,顺便和大家分享交流. 参考书籍<IAD PRO权威指南> 工具: PETools: ETools 是另一款很好的PE文件编辑工具,以前 ...

  3. nginx isis

    Nginx+IIS简单的部署   随着互联网项目用户访问量不断上升,单点web服务器是无法满足大型高并发高负载的业务处理的,为了给web服务器做负载均衡方案,打算采用Nginx搭建负载均衡服务器,把用 ...

  4. js中的执行环境和作用域链

    首先介绍一些即将用到的概念: 执行环境:  它定义了变量和函数有权访问其他数据的范围,每一个执行环境都有一个与之关联的变量对象,环境中定义的所有变量和函数都保存在这个变量对象中.   所有javasc ...

  5. ORACLE——日期时间格式化参数详解 之二

    2.8 DD 指定日期在当月中第几天(范围:1-31) SQL> select to_char(sysdate,'DD YYYY-MM-DD PM hh24:mi:ss ') from dual ...

  6. 在Linux下adb连接不上android手机的终极解决方案

    转自: http://blog.csdn.net/liuqz2009/article/details/7942569 1.做android开发的过程,碰到了Linux下adb识别不了android设备 ...

  7. win10获取超级管理员权限脚本实现

    建立一个TXT文件,把下面的脚本贴到里面,然后把后缀改成reg格式,双击添加到注册表就可以了, win10_1703版本亲测可用.... Windows Registry Editor Version ...

  8. session跨域共享

    www.maxomnis.com的index.php文件内容 <?phpsession_start();setcookie("user", "alex proter ...

  9. ROS Learning-010 beginner_Tutorials 编写简单的启动脚本文件(.launch 文件)

    ROS Indigo beginner_Tutorials-09 编写简单的启动脚本文件 我使用的虚拟机软件:VMware Workstation 11 使用的Ubuntu系统:Ubuntu 14.0 ...

  10. docker学习(1)docker的安装

    原文地址:http://blog.csdn.net/we_shell/article/details/38352837 1. 前言 Docker的英文本意是“搬运工”,在程序员的世界里,Docker搬 ...