题目大意
给定 l,rl,rl,r,求 ∑i=lr∑k∣i1\sum_{i=l}^r\sum_{k|i}1i=l∑rk∣i∑1
数据范围 1⩽l,r⩽1.6×10143 second1\leqslant l,r\leqslant 1.6\times 10^{14}\quad3\ \text{second}1⩽l,r⩽1.6×10143 second
题解
可以发现, 原式等价于:
Sumd(r)−Sumd(l−1)\text{Sum}_{d}(r)-\text{Sum}_{d}(l-1)Sumd(r)−Sumd(l−1)其中 ddd 是约数个数函数。
某些学过杜教筛的(比如我)会开始考虑,然后发现打死都想不出来(至少我想不出来)……可能有的大佬想出来了,结果时间复杂度是 Θ(n23)\Theta(n^{\frac 23})Θ(n32),发现死都卡不过去……好吧。
Sumd(n)=∑i=1n∑k∣i1=∑k=1n∑k∣ii⩽n1=∑k=1n⌊nk⌋\begin{aligned}
\text{Sum}_{d}(n)&=\sum_{i=1}^n\sum_{k|i}1\\
&=\sum_{k=1}^n\sum_{k|i}^{i\leqslant n}1\\
&=\sum_{k=1}^n\Big\lfloor\frac nk \Big\rfloor\\
\end{aligned}Sumd(n)=i=1∑nk∣i∑1=k=1∑nk∣i∑i⩽n1=k=1∑n⌊kn⌋
心情舒畅。除法分块,时间复杂度 Θ(n)\Theta(\sqrt n)Θ(n) 。
#include<bits/stdc++.h>
using namespace std;
#define mod 998244353
long long ds(long long n){
long long ans=0;
for(long long l=1,r;l<=n;l=r+1){
r=n/(n/l); if(r>n) r=n;
ans+=(n/l)*(r-l+1);
ans=ans%mod;
} return ans;
}
int main(void){
long long l,r;
scanf("%lld%lld",&l,&r);
printf("%lld",(ds(r)-ds(l-1)+mod)%mod);
return 0;
}