【SP26073】DIVCNT1 - Counting Divisors 题解

题目描述

定义 \(d(n)\)\(n\) 的正因数的个数,比如 \(d(2) = 2, d(6) = 4\)

令 $ S_1(n) = \sum_{i=1}^n d(i) $

给定 \(n\),求 \(S_1(n)\)

输入格式

第一行包含一个正整数 \(T\) (\(T \leq 10^5\)),表示数据组数。

接下来的 \(T\) 行,每行包含一个正整数 \(n\) (\(n < 2^{63}\))。

输出格式

对于每个 \(n\),输出一行一个整数,表示 \(S_1(n)\) 的值。

题解

显然 $ S_1(n) = \sum_{i=1}^n \left \lfloor \frac ni \right \rfloor $
整除分块可以做到\(O \left( \sqrt n \right)\),这是要死的复杂度。
但实际上,这玩意是有个优化套路的:
显然有$ \sum_{i=1}^n \left \lfloor \frac ni \right \rfloor = 2 \sum_{i=1}^{\lfloor \sqrt n \rfloor} \left \lfloor \frac ni \right \rfloor - \left \lfloor \sqrt n \right \rfloor^2 $
那么只需求 \(\sum\limits_{i=1}^{\lfloor \sqrt n \rfloor} \left \lfloor \dfrac ni \right \rfloor\) 的值
它显然等于 \(f(x) = \dfrac n x\)、直线 \(y = \sqrt n\)\(x\) 轴和 \(y\) 轴所围成的区域 \(R\) 中整点 (格点) 的个数 (含边界,\(x\) 轴除外)。我们把它变成了一个区间数点问题。

但实际上这个函数是个凸函数,因此区域 \(R\) 的补集 \(R'\) 为一个凸集,我们很显然的想到用凸包去拟合,然后Pick定理随便搞一搞。

怎么找凸包呢?我们用SBT大力求斜率,然后弄个单调栈去搞。
\(B = \left \lfloor \sqrt n \right \rfloor\),我们从点 \(P_0 \left( \left \lfloor \dfrac nB \right \rfloor, B+1 \right)\) 开始,一步一步寻找凸包上所有的点。
(步骤一)我们在栈中加入两个分数 (为斜率的绝对值) \(\dfrac 01\)\(\dfrac 11\),代表向量 \((1, 0)\)\((1, 1)\),由于 \(f' \left( \sqrt n \right) = -1\),因此这部分所有斜率都在 \(-1 \sim 0\) 之间。 此外,这个栈需要满足自顶向上是单调递增的。
(步骤二)接下来,我们取出栈顶向量,将 \(P_0\) 持续与这个向量 (关于 \(x\) 轴的对称,下略) 相加,直到这个点 \(P_k\) 不在区域 \(R'\) 中 (即在区域 \(R\) 中)。由于这些分数是在 Stern-Brocot 树中产生的,因此一定是既约分数 (即分子与分母互素)。
因此每加一步,我们可以计算出这个横条的面积:设向量为 \((u, v)\),上一个点 (\(P_{k-1}\)) 的横坐标为 \(x\),则面积为 \(x v + \dfrac 12 (v + 1) (u - 1)\)
(步骤三)接着我们要对栈进行调整。由于函数的斜率的绝对值单调递减,因此栈中的分数也需要单调递减。
故我们需要把值过大的分数弹出栈外,直到栈顶和它下面的元素与 \(P_k\) 相加后,前者在 \(R'\) 外,后者在 \(R'\) 内。把这两个向量记作 \(l\)\(r\)
(步骤四)然后我们在SBT上二分(不是说大力求嘛).
\(l = \dfrac {y_l} {x_l}, r = \dfrac {y_r} {x_r}\) (\(l > r\)),则 \(m = \dfrac {y_m} {x_m} = \dfrac {y_l + y_r} {x_l + x_r}\)。令 \(M = P_k + m\) (即 \(P_k\) 按照向量 \(m\) 平移后的点),如果 \(M\)\(R'\) 中,则将 \(r\) 压入栈后令 \(r \gets m\),继续二分;否则,分以下两种情况讨论(二轮判断):
一:如果 \(\left| f' \left( x_k + x_m \right) \right| \leq r\) (其中 \(x_k\)\(P_k\) 的横坐标)——由 \(f'(x) = - \dfrac n {x^2}\) 可得该条件等价于 \(n x_r \leq (x_k + x_m)^2 y_r\) ——则容易得到如果再迭代下去的话,所有的 \(P_k + m\) 都不会落在 \(R'\) 内,也就能说已经二分完毕了,因此只需保留当前的栈重新回到步骤 2 进入下一轮迭代。
二:如果 \(\left| f' \left( x_k + x_m \right) \right| > r\),则接下来的向量还有可能落入 \(R'\) 中,因此令 \(l \gets m\) 后继续二分。

这个做法的复杂度上界不超过 \(O \left( n^{1/3} \log n \right)\) ,因为斜率只有不超过\(O \left( n^{1/3} \right)\)个。(至于怎么证明文文也不会)。
后期函数的斜率非常小,都是 \(\dfrac 1k\) 的形式,会退化为 \(O(y)\),因此可以在 \(y \leq \sqrt[3]n\) 的部分中直接暴力计算

Code

#include <bits/stdc++.h>
const int N=1000005;
typedef long long ll;
struct qwq {ll x, y;qwq (ll x0 = 0, ll y0 = 0) : x(x0), y(y0) {}inline qwq operator + (const qwq &B) const {return qwq(x + B.x, y + B.y);}
};
ll n;
int top;
qwq stk[N];
inline void push(qwq x) { stk[++top]=x;}
inline void putint(__int128 x) {static char buf[36];if (!x) {putchar(48); return;} int i = 0;for (; x; buf[++i] = x % 10 | 48, x /= 10);for (; i; --i) putchar(buf[i]);
}inline bool check(ll x, ll y) {return n < x * y;}inline bool judge(ll x, qwq v) {return (__int128)n * v.x <= (__int128)x * x * v.y;}__int128 S1() {int i, crn = cbrt(n);ll srn = sqrt(n), x = n / srn, y = srn + 1;__int128 ret = 0;qwq L, R, M;push(qwq(1, 0)); push(qwq(1, 1));while(true) {for (L = stk[top--]; check(x + L.x, y - L.y); x += L.x, y -= L.y)ret += x * L.y + (L.y + 1) * (L.x - 1) / 2;if (y <= crn) break;for (R = stk[top]; !check(x + R.x, y - R.y); R = stk[--top]) L = R;for (; M = L + R, 1; )if (check(x + M.x, y - M.y)) push(R = M);else {if (judge(x + M.x, R)) break;L = M;}}for (i = 1; i < y; ++i) ret += n / i;return ret*2-srn*srn;
}
int main() {int T;for (scanf("%d", &T); T; --T) {scanf("%lld", &n); putint(S1());puts("");}return 0;
}

转载于:https://www.cnblogs.com/Syameimaru/p/10197934.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/426082.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

密码系统的安全性

1&#xff0c;评估密码系统安全性主要有三种方法&#xff1a; &#xff08;1&#xff09;无条件安全性 这种评价方法考虑的是假定攻击者拥有无限的计算资源&#xff0c;但仍然无法破译该密码系统。 &#xff08;2&#xff09;计算安全性 这种方法是指使用目前最好的方法攻破…

java学习(135):map中泛型使用

定义一个员工类 public class Employee {private String name;private String ags;public void setName(String name) {this.name name;}public String getName() {return name;}public void setAgs(String ags) {this.ags ags;}public String getAgs() {return ags;} }定义…

java两种绑定方式_Javascript绑定事件的两种方式的区别

命名函数function check(){//code}匿名函数window.onload function(){//先获取元素对象&#xff0c;再绑定事件&#xff0c;绑定的是匿名函数不可重用var btn document.getElementById("btn");btn.onclick function(){//code}}以前一直以为两种方式的区别不大&…

前端基础_认识前端.md

前端学习 前端学习路线学习网站 菜鸟驿站慕课网freeCOdeCampw3schooltry8在线编辑 codepenjsfiddlethecodeplayer其他网站 cssfilterscssstats极客学院搭建个人博客wordpress博客园网站检查规范How to learn webTobe continue... 学习准备 查看浏览器占有的市场份额 查看浏览器…

[剑指offer][JAVA][第62题][约瑟夫环][LinkedList vs ArrayList]

【问题描述】 面试题62. 圆圈中最后剩下的数字 0,1,,n-1这n个数字排成一个圆圈&#xff0c;从数字0开始&#xff0c;每次从这个圆圈里删除第m个数字。求出这个圆圈里剩下的最后一个数字。例如&#xff0c;0、1、2、3、4这5个数字组成一个圆圈&#xff0c;从数字0开始每次删除第…

java创建两个foo方法_Java类实例化原理 - osc_foo7glsg的个人空间 - OSCHINA - 中文开源技术交流社区...

Java对象的创建过程包括类初始化(类实例化两个阶段。一、Java对象创建时机(1)使用new关键字创建对象(2)反射创建对象使用Class类的newInstance方法Student student2 (Student)Class.forName("Student类全限定名").newInstance()&#xff1b;使用Constructor类的newI…

java学习(136):带泛型的类

SuppressWarnings("all") public class GJClass<T> {public String getClassName(T t){return t.getClass().getName();} } 测试类 public class test76 {public static void main(String[] args){GJClass gjClassnew GJClass();String classNamegjClass.get…

如何往eclipse中导入maven项目

现在公司中大部分项目可能都是使用maven来构建&#xff0c;假如现在摆在你面前有一个maven的项目&#xff0c;如果你要学习它&#xff0c;如何将它导入到像eclipse这样的集成开发工具中呢&#xff0c;以项目public_class_1为例&#xff1a; 1.在eclipse的工作界面的最左侧&…

[Leetcode][JAVA][第912题][排序算法]

【问题描述】 给你一个整数数组 nums&#xff0c;将该数组升序排列。 示例 1&#xff1a; 输入&#xff1a;nums [5,2,3,1] 输出&#xff1a;[1,2,3,5]【解答思路】 1.插入排序&#xff08;熟悉&#xff09; 每次将一个数字插入一个有序的数组里&#xff0c;成为一个长度更…

java 调用r语言包传参数_Java与R语言的配置,调用

我是最近才接触到了R语言&#xff0c;所以用起来有很多的问题&#xff0c;之前只是想单纯想用java调用到R语言中的一些东西&#xff0c;没有想到这个事情并不是想象的那么简单的。好了&#xff0c;闲话不多说&#xff0c;下面我来说说我在运用R的时候遇上的问题吧。第一步&…

玩转oracle 11g(42):增加表空间

--查询表空间 select t.tablespace_name, d.file_name, d.autoextensible, d.maxbytes, d.status from dba_tablespaces t, dba_data_files d where t.tablespace_name d.tablespace_name order by tablespace_name.file_name; --增加表空间 AL…

php下载文件添加header响应头

header(Content-type:application/octet-stream);header(Content-Disposition:attachment;filename".basename($file).");header(Content-Length:.filesize($file));readfile($file);转载于:https://www.cnblogs.com/jielin/p/10203140.html

[Leetcode][JAVA][第1111题][栈思想]

【问题描述】 有效括号字符串 定义&#xff1a;对于每个左括号&#xff0c;都能找到与之对应的右括号&#xff0c;反之亦然。详情参见题末「有效括号字符串」部分。嵌套深度 depth 定义&#xff1a;即有效括号字符串嵌套的层数&#xff0c;depth(A) 表示有效括号字符串 A 的嵌…

玩转oracle 11g(43):oracle导出空表

因为11G数据库在CREATE表后数据库不会立刻给该表分配物理存储空间&#xff0c;所以导出数据库的时候自然而然不会导出该表。 解决方案&#xff1a;在导出表服务器上找出所有数据为空的表&#xff0c;批处理的给没有数据行的数据表分配存储空间。 方法1.此为分步骤执行&#x…

分类器交叉验证java_使用交叉验证的KNN分类器

首先&#xff0c;您需要准确定义您的任务 . F.ex给出R ^(MxN)中的图像I&#xff0c;我们希望将I分类为包含面部的图像或没有面部的图像 .我经常使用像素分类器&#xff0c;其任务类似于&#xff1a;对于图像&#xff0c;我决定每个像素是面像素还是非面像素 .定义任务的一个重要…

Python——assert(断言函数)

一、断言函数的作用 python assert断言是声明其布尔值必须为真的判定&#xff0c;如果发生异常就说明表达示为假。可以理解assert断言语句为raise-if-not&#xff0c;用来测试表示式&#xff0c;其返回值为假&#xff0c;就会触发异常。 二、常用格式 assert 11  assert 222*…

[Leetcode][JAVA][第20题][Stack][Map]

【问题描述】 20. 有效的括号 给定一个只包括 (&#xff0c;)&#xff0c;{&#xff0c;}&#xff0c;[&#xff0c;] 的字符串&#xff0c;判断字符串是否有效。有效字符串需满足&#xff1a;左括号必须用相同类型的右括号闭合。 左括号必须以正确的顺序闭合。 注意空字符串可…

java学习(137):java异常初识

//java异常初识 public class test78 {public static void main(String[] args) {countArraylength( -1 );}public static int countArraylength(int length) {int[] nums new int[length];return nums.length;} } 运行结果

Java如何随机出石头剪刀布_JAVA编程实现石头剪刀布

我不是焊工import java.util.Scanner;public class Jsb {public static void main(String[] args) {while (true) {result(input(), random());System.out.println("");}}public static int input() {System.out.println("请输入&#xff1a;1-剪刀&#xff0c;…

java学习(138):异常处理

//异常 public class test79 {//定义方法声明定义异常&#xff0c;在满足条件时抛出异常对象&#xff0c;程序转向异常处理public double count(double n,double m)throws Exception {if (m 0) {//如果除数等于0.则抛出异常实例throw new Exception("对不起。除数不能等…