Loading [MathJax]/jax/output/CommonHTML/jax.js

『约数之和 整除分块』

Parsnip·2019-04-20 16:20·352 次阅读

『约数之和 整除分块』

<更新提示>

<第一次更新>


<正文>

余数之和#

Description#

给出正整数n和k,计算j(n, k)=k mod 1 + k mod 2 + k mod 3 + … + k mod n的值

其中k mod i表示k除以i的余数。

例如j(5, 3)=3 mod 1 + 3 mod 2 + 3 mod 3 + 3 mod 4 + 3 mod 5=0+1+0+3+3=7

Input Format#

输入仅一行,包含两个整数n, k。

1<=n ,k<=10^9

Output Format#

输出仅一行,即j(n, k)。

Sample Input#

Copy
5 3

Sample Output#

Copy
7

解析#

注意到k%i=kkii,故$$\sum_{i=1}^n k%i=nk-\sum_{i=1}^n\lfloor \frac{k}{i} \rfloori$$

那么问题即求ni=1kii

引理:对于i[x,kkx]ki的值都相等,其证明如下:

f(x)=kkx,显然有f(x)k(kx)=x,则可得kf(x)kx

从另一方面考虑,则有kf(x)kkk/x=kx,则可得kf(x)=kx

这样,每一次累加[x,kkx]所对应的值即可,可以证明这样的段不超过2k个,我们称这种优化算法为整除分块

Code:

Copy
#include<bits/stdc++.h> using namespace std; long long n,k,ans; inline void input(void) { scanf("%lld%lld",&n,&k); } inline void solve(void) { ans=n*k; for (long long l=1,r;l<=n;l=r+1) { r = k/l ? min(k/(k/l),n) : n; ans -= (k/l)*(l+r)*(r-l+1)/2; } } int main(void) { input(); solve(); printf("%lld\n",ans); return 0; }

<后记>

posted @   Parsnip  阅读(352)  评论(0编辑  收藏  举报
编辑推荐:
· 从二进制到误差:逐行拆解C语言浮点运算中的4008175468544之谜
· .NET制作智能桌面机器人:结合BotSharp智能体框架开发语音交互
· 软件产品开发中常见的10个问题及处理方法
· .NET 原生驾驭 AI 新基建实战系列:向量数据库的应用与畅想
· 从问题排查到源码分析:ActiveMQ消费端频繁日志刷屏的秘密
阅读排行:
· 《HelloGitHub》第 108 期
· Windows桌面应用自动更新解决方案SharpUpdater5发布
· 我的家庭实验室服务器集群硬件清单
· C# 13 中的新增功能实操
· Supergateway:MCP服务器的远程调试与集成工具
点击右上角即可分享
微信分享提示
目录