题目链接

https://www.51nod.com/Challenge/Problem.html#!#problemId=1238

题解

本来想做个杜教筛板子题结果用另一种方法过了......

所谓的“另一种方法”用到的一些技巧还是挺不错的,因此这里简单介绍一下。

首先还是基本的推式子:

\[\begin{aligned}\sum_{i = 1}^n \sum_{j = 1}^n {\rm lcm}(i, j) &= \sum_{i = 1}^n \sum_{j = 1}^n \frac{ij}{{\rm gcd}(i, j)} \\ &= \sum_{d = 1}^{n} \sum_{i = 1}^n \sum_{j = 1}^n[{\rm gcd}(i, j) = d]\frac{ij}{d} \\ &= \sum_{d = 1}^n d\sum_{i = 1}^{\left\lfloor\frac{n}{d}\right\rfloor}\sum_{j = 1}^{\left\lfloor\frac{n}{d}\right\rfloor}[{\rm gcd}(i, j) = 1]ij\end{aligned}
\]

设 \(f(x) = \sum_\limits{i = 1}^x \sum_\limits{j = 1}^x [{\rm gcd}(i, j) = 1]ij\),那么答案即为 \(\sum_\limits{d = 1}^n d\times f(\left\lfloor\frac{n}{d}\right\rfloor)\)。显然答案可以数论分块求,因此我们的任务就是求 \(f\) 函数。

首先考虑当 \(x\) 较小时,我们能否直接预处理出 \(f(x)\)。考虑差分:当 \(x > 1\) 时,\(f(x)\) 较 \(f(x - 1)\) 而言,多了的部分为:$$\left(\sum_\limits{i = 1}^x\sum_\limits{j = 1}^x [{\rm gcd}(i, j) = 1]ij\right) - \left(\sum_\limits{i = 1}^{x - 1}\sum_\limits{j = 1}^{x - 1} [{\rm gcd}(i, j) = 1]ij\right) = 2x \sum_{i = 1}^x [{\rm gcd}(i, x) = 1]i$$

而由于小于等于 \(x(x > 1)\) 且与 \(x\) 互质的数的和为 \(\frac{\varphi(x)x}{2}\)(证明提示:当 \(n \geq 2\) 时,若 \({\rm gcd}(d, n) = 1\) 必然有 \({\rm gcd}(n - d, n) = 1\),与 \(n\) 互质的 \(d\) 共有 \(\varphi(n)\) 个),因此我们就得到了 \(f(x)\) 的递推式:\(f(x) = f(x - 1) + 2x \times \frac{\varphi(x)x}{2}\),即 \(f(x) = f(x - 1) + \varphi(x)x^2\)。

不过这只能处理 \(x\) 较小的情况。当 \(x\) 较大时,我们仍然得另谋他路。在 \(f(x) = \sum_\limits{i = 1}^x \sum_\limits{j = 1}^x [{\rm gcd}(i, j) = 1]ij\) 当中,对 \(f(x)\) 有贡献的 \(i, j\) 满足 \(i\) 与 \(j\) 是互质的,我们尝试着使用补集转化,用总和减去不互质的 \(i, j\) 的贡献:

\[\begin{aligned} f(x) &= \sum_{i = 1}^x\sum_{j = 1}^x ij - \sum_{d = 2}^x \sum_{i = 1}^x \sum_{j = 1}^x [{\rm gcd}(i, j) = d]ij \\ &= \left(\frac{x(x+1)}{2}\right)^2 - \sum_{d = 2}^x d^2 \sum_{i = 1}^{\left\lfloor\frac{x}{d}\right\rfloor} \sum_{j = 1}^{\left\lfloor\frac{x}{d}\right\rfloor} [{\rm gcd}(i, j) = 1]ij \\ &=\left(\frac{x(x+1)}{2}\right)^2 - \sum_{d = 2}^x d^2 f(\left\lfloor\frac{x}{d}\right\rfloor) \end{aligned}
\]

这样,我们就能够递归地去求解当 \(x\) 较大时 \(f(x)\) 的值了。不难发现,该求解方法的时间复杂度和杜教筛是一样的,为 \(O(n^{\frac{2}{3}})\),且非常好写。

代码

#include<bits/stdc++.h>

using namespace std;

const int mod = 1000000007, inv2 = 500000004, inv6 = 166666668, up = 4641589, md = 1000003;

int main() {
function<int (int, int)> mul = [&] (int x, int y) {
return (long long) x * y % mod;
};
function<void (int&, int)> add = [&] (int& x, int y) {
x += y;
if (x >= mod) {
x -= mod;
}
};
function<void (int&, int)> sub = [&] (int& x, int y) {
x -= y;
if (x < 0) {
x += mod;
}
};
vector<bool> is_prime(up, true);
vector<int> phi(up), primes;
phi[1] = 1;
for (int i = 2; i < up; ++i) {
if (is_prime[i]) {
primes.push_back(i);
phi[i] = i - 1;
}
for (auto v : primes) {
int d = v * i;
if (d >= up) {
break;
}
is_prime[d] = false;
if (i % v == 0) {
phi[d] = mul(phi[i], v);
break;
} else {
phi[d] = mul(phi[i], phi[v]);
}
}
}
for (int i = 2; i < up; ++i) {
phi[i] = mul(mul(phi[i], i), i);
add(phi[i], phi[i - 1]);
}
function<int (long long)> sum_pow2 = [&] (long long n) {
n %= mod;
return mul(mul(mul(n, n + 1), (n * 2 + 1)), inv6);
};
vector<pair<long long, int>> value[md];
function<int (long long)> find = [&] (long long v) {
int p = v % md;
for (auto e : value[p]) {
if (e.first == v) {
return e.second;
}
}
return -1;
};
function<void (long long, int)> insert = [&] (long long v, int result) {
value[v % md].emplace_back(v, result);
};
function<int (long long)> f = [&] (long long n) {
int returned = find(n);
if (~returned) {
return returned;
} else {
if (n < up) {
return phi[n];
} else {
int result = 0, x = n % mod;
x = mul(mul(x, x + 1), inv2);
result = mul(x, x);
for (long long i = 2, last; i <= n; i = last + 1) {
last = n / (n / i);
sub(result, mul((sum_pow2(last) - sum_pow2(i - 1) + mod) % mod, f(n / i)));
}
insert(n, result);
return result;
}
}
};
long long n;
scanf("%lld", &n);
int answer = 0;
for (long long i = 1, last; i <= n; i = last + 1) {
last = n / (n / i);
add(answer, mul(mul(mul((i + last) % mod, (last - i + 1) % mod), inv2), f(n / i)));
}
printf("%d\n", answer);
return 0;
}

51nod1238. 最小公倍数之和 V3(数论)的更多相关文章

  1. 51nod1238 最小公倍数之和 V3 莫比乌斯函数 杜教筛

    题意:求\(\sum_{i = 1}^{n}\sum_{j = 1}^{n}lcm(i, j)\). 题解:虽然网上很多题解说用mu卡不过去,,,不过试了一下貌似时间还挺充足的,..也许有时间用phi ...

  2. [51Nod1238]最小公倍数之和 V3[杜教筛]

    题意 给定 \(n\) ,求 \(\sum_{i=1}^n \sum_{j=1}^n lcm(i,j)\). \(n\leq 10^{10}\) 分析 推式子 \[\begin{aligned} an ...

  3. [51nod1238]最小公倍数之和V3

    来自FallDream的博客,未经允许,请勿转载,谢谢. ----------------------------------------------------------------------- ...

  4. 51nod1238 最小公倍数之和 V3(莫比乌斯反演)

    题意 题目链接 Sol 不想打公式了,最后就是求一个 \(\sum_{i=1}^n ig(\frac{N}{i})\) \(g(i) = \sum_{i=1}^n \phi(i) i^2\) 拉个\( ...

  5. 51nod1238 最小公倍数之和 V3

    又被这神仙题给坑爆了. 神仙题解. 一开始我把lcm变成ij/gcd然后按照常规套路去推,推到最后发现不是miu * Id而是miu · Id......这还搞鬼啊. 正解居然跟这个差不多,先转成求其 ...

  6. [51nod1238] 最小公倍数之和 V3(杜教筛)

    题面 传送门 题解 懒了--这里写得挺好的-- //minamoto #include<bits/stdc++.h> #define R register #define ll long ...

  7. 51NOD 1238 最小公倍数之和 V3 [杜教筛]

    1238 最小公倍数之和 V3 三种做法!!! 见学习笔记,这里只贴代码 #include <iostream> #include <cstdio> #include < ...

  8. 51nod 1238 最小公倍数之和 V3

    51nod 1238 最小公倍数之和 V3 求 \[ \sum_{i=1}^N\sum_{j=1}^N lcm(i,j) \] \(N\leq 10^{10}\) 先按照套路推一波反演的式子: \[ ...

  9. 51 NOD 1238 最小公倍数之和 V3

    原题链接 最近被51NOD的数论题各种刷……(NOI快到了我在干什么啊! 然后发现这题在网上找不到题解……那么既然A了就来骗一波访问量吧…… (然而并不怎么会用什么公式编辑器,写得丑也凑合着看吧…… ...

随机推荐

  1. Python正则表达式的七个使用范例-乾颐堂

    作为一个概念而言,正则表达式对于Python来说并不是独有的.但是,Python中的正则表达式在实际使用过程中还是有一些细小的差别. 本文是一系列关于Python正则表达式文章的其中一部分.在这个系列 ...

  2. python 的输入和输出

    内置函数:raw_inpurt('place input') print getpass  隐藏输入密码 import getpass pwd = getpass.getpass("> ...

  3. Linux Mint 17使用配置

    => 调亮度: 方法一: 每次开机或注销登录之后需要重新设置 > /sys/class/backlight/intel_backlight/brightness #根据自己需要调值,如20 ...

  4. DapperExtensions 使用教程

    最近搭建一个框架,使用dapper来做数据库访问,数据是sql server2012,支持多个数据库.事务.orm.ado.net原生操作方式,非常方便. 使用dapper的原因网上有很多文章说明,这 ...

  5. 去除SVN图标并解除svn控制 (转)

    今天一不小心把F盘弄成了SVN管理项目,结果如图: 看到这个,当场晕菜,经过不懈的努力终于找到一种方法,如下: 右键  ===>TortoiseSVN   ===>Settings 点击确 ...

  6. php 用csv文件导出大量数据初方案

    背景:接手的项目中支持导出一批数据,全数量在50W左右.在接手的时候看代码是直接一次查询MySQL获得数据,然后用header函数直接写入csv,用户开始导出则自动下载.但是,在全导出的时候,功能出现 ...

  7. Linux软件包的管理

    RPM软件包 RPM软件包一般的安装位置(分散): 管理程序:/sbin/* /usr/sbin/* 普通用户程序:/bin/* /usr/bin/* rpm -q ===> rpm -quer ...

  8. C++11中的tuple应用:让函数返回多个值

    在没有tuple之前,如果函数需要返回多个值,则必须定义一个结构体,有了C++11,可以基于tuple直接做了,下面是个示例: // 编译:g++ -std=c++11 -g -o x x.cpp # ...

  9. [Selenium With C#基础教程] Lesson-05 文本框

    作者:Surpassme 来源:http://www.jianshu.com/p/7dca7d0d1ea3 声明:本文为原创文章,如需转载请在文章页面明显位置给出原文链接,谢谢. 文本框在Web页面中 ...

  10. 异步IO类

    也学习多线程一段时间了,也写了几个简单实用的功能类,也意思到细节的处理的重要性,现在就让我们来写一个稍稍更有用的异步IO的类. 本来想参考Java NIO 中的类,Java NIO作为新io包,本身提 ...