P2261 [CQOI2007]余数求和 题解
在看到这道题后,首先想到直接暴力的做法,但显然在面对 109 时会 TLE 。
由此我们可以想到数论分块的做法。
出题人十分热心,在题干后加上了一句颇为显然但易被忽略的性质:
其中 kmod 表示 k 除以 i 的余数。
形式化的,它表示 k\bmod i\Leftrightarrow k\ -\ \left\lfloor\dfrac{k}{i}\right\rfloor \times i 。
应用这一重要性质,我们可以对题中所给公式进行如下变形:
G(n,k)=\sum_{i=1}^nk\ -\ \left\lfloor\dfrac{k}{i}\right\rfloor \times i
再将 k 进行提取,可得:
G(n,k)=n\times k-\sum_{i=1}^n\left\lfloor\dfrac{k}{i}\right\rfloor \times i
可以发现,\left\lfloor\dfrac{k}{i}\right\rfloor 的得数呈块状,在写代码时注意枚举左右边界即可。
注意:可能有 \left\lfloor\dfrac{k}{i}\right\rfloor=0 的情况出现,请注意在代码实现过程中特判。
View code:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ri register int
#define il inline
#define int long long
int n,k,ans=0;
il ll read(){
ll x=0,y=1;
char c=getchar();
while(c<'0'||c>'9'){
if(c=='-')
y=-1;
c=getchar();
}
while(c>='0'&&c<='9'){
x=x*10+c-'0';
c=getchar();
}
return x*y;
}
signed main(){
n=read(),k=read();
ans=n*k;
for(ri i=1,j;i<=n;i=j+1){
if(k/i)
j=min(k/(k/i),n);
else
j=n;
ans-=(k/i)*(i+j)*(j-i+1)/2;
}
printf("%lld",ans);
return 0;
}
【推荐】博客园的心动:当一群程序员决定开源共建一个真诚相亲平台
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】Flutter适配HarmonyOS 5知识地图,实战解析+高频避坑指南
【推荐】开源 Linux 服务器运维管理面板 1Panel V2 版本正式发布
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Java线程池详解:高效并发编程的核心利器
· 从“看懂世界”到“改造世界”:AI发展的四个阶段你了解了吗?
· 协程本质是函数加状态机——零基础深入浅出 C++20 协程
· 编码之道,道心破碎。
· 记一次 .NET 某发证机系统 崩溃分析
· 这5种规则引擎,真香!
· 基于.net6的一款开源的低代码、权限、工作流、动态接口平台
· 【好用推荐】免费在线图片压缩工具,附源码
· 纯C#软实现openGL(V0.1),黑盒变白盒
· Claude Code 初体验 - Windows