【ybtoj高效进阶6-2-5】余数之和 /【luogu P2261】 [CQOI2007] 余数求和
题目大意:
给定 n n n , k k k,求 ∑ i = 1 n k m o d i \sum\limits_{i=1}^{n}k \bmod i i=1∑nkmodi
思路:
先来分析一下整除分块这种东西
根据取模运算的性质,
x
m
o
d
y
=
x
−
y
∗
⌊
x
y
⌋
x\bmod y=x-y*\left \lfloor \frac{x}{y} \right \rfloor
xmody=x−y∗⌊yx⌋
则原式=
∑
i
=
1
n
k
−
i
∗
⌊
i
k
⌋
=
n
∗
k
−
∑
i
=
1
n
i
∗
⌊
i
k
⌋
\sum\limits_{i=1}^{n}k-i*\left \lfloor \frac{i}{k} \right \rfloor=n*k-\sum\limits_{i=1}^{n}i*\left \lfloor \frac{i}{k} \right \rfloor
i=1∑nk−i∗⌊ki⌋=n∗k−i=1∑ni∗⌊ki⌋
右半部分可以使用整除分块处理
整除分块:
第一个结论:对于
a
,
b
,
c
∈
Z
a,b,c\in Z
a,b,c∈Z
⌊
a
b
c
⌋
=
⌊
⌊
a
b
⌋
c
⌋
\left \lfloor \frac{a}{bc} \right \rfloor=\left \lfloor \frac{\left \lfloor \frac{a}{b} \right \rfloor}{c} \right \rfloor
⌊bca⌋=⌊c⌊ba⌋⌋
证明:
a
b
=
⌊
a
b
⌋
+
x
,
x
∈
[
0
,
1
)
\frac{a}{b}=\left \lfloor \frac{a}{b} \right \rfloor+x,x\in[0,1)
ba=⌊ba⌋+x,x∈[0,1)
∵
⌊
a
b
c
⌋
=
⌊
a
b
∗
1
c
⌋
=
⌊
1
c
∗
(
⌊
a
b
⌋
+
x
)
⌋
=
⌊
⌊
a
b
⌋
c
+
x
c
⌋
\because\left \lfloor \frac{a}{bc} \right \rfloor=\left \lfloor \frac{a}{b} *\frac{1}{c}\right \rfloor=\left \lfloor \frac{1}{c} *(\left \lfloor \frac{a}{b} \right \rfloor+x)\right \rfloor=\left \lfloor \frac{\left \lfloor \frac{a}{b} \right \rfloor}{c}+\frac{x}{c} \right \rfloor
∵⌊bca⌋=⌊ba∗c1⌋=⌊c1∗(⌊ba⌋+x)⌋=⌊c⌊ba⌋+cx⌋
显然
x
c
<
1
\frac{x}{c}<1
cx<1, 对答案没有影响,直接舍去即可
然后就可以开始愉快的分块了
对于
⌊
n
i
⌋
=
⌊
n
j
⌋
,
0
<
i
≤
j
≤
n
\left \lfloor \frac{n}{i} \right \rfloor=\left \lfloor \frac{n}{j} \right \rfloor,0<i\leq j\leq n
⌊in⌋=⌊jn⌋,0<i≤j≤n
这时候我们要找到最大的
j
j
j 值
令
k
=
⌊
n
i
⌋
k=\left \lfloor \frac{n}{i} \right \rfloor
k=⌊in⌋,则有
k
≤
n
i
k\leq\frac{n}{i}
k≤in
∴
⌊
n
k
⌋
≥
⌊
n
n
i
⌋
=
⌊
i
⌋
=
i
\therefore \left \lfloor \frac{n}{k} \right \rfloor\geq\left \lfloor \frac{n}{\frac{n}{i}} \right \rfloor=\left \lfloor i\right \rfloor=i
∴⌊kn⌋≥⌊inn⌋=⌊i⌋=i
∴
j
=
m
a
x
,
i
m
a
x
=
i
=
⌊
n
k
⌋
=
⌊
n
⌊
n
i
⌋
⌋
\therefore j=max,i_{max}=i=\left \lfloor \frac{n}{k} \right \rfloor=\left \lfloor \frac{n}{\left \lfloor \frac{n}{i} \right \rfloor} \right \rfloor
∴j=max,imax=i=⌊kn⌋=⌊⌊in⌋n⌋
Q
E
D
QED
QED
那么对于
⌊
n
i
⌋
\left \lfloor \frac{n}{i} \right \rfloor
⌊in⌋相同的多个
i
i
i 我们就可以打包计算了,
⌊
n
i
⌋
\left \lfloor \frac{n}{i} \right \rfloor
⌊in⌋最多只有
n
\sqrt{n}
n 种情况(显然我不会证明)
那么整个算法的时间复杂度就是
O
(
n
)
O(\sqrt n)
O(n)了
代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cstring>
#include<vector>
#include<cmath>
#include<ctime>
#define r register
#define rep(i,x,y) for(r ll i=x;i<=y;++i)
#define per(i,x,y) for(r ll i=x;i>=y;--i)
using namespace std;
typedef long long ll;
ll n,k;
inline ll in()
{
ll res=0,f=1;
char ch;
while((ch=getchar())<'0'||ch>'9')
if(ch=='-') f=-1;
res=res*10+ch-48;
while((ch=getchar())>='0'&&ch<='9')
res=res*10+ch-48;
return res*f;
}
int main()
{
n=in(),k=in();
ll ans=n*k;
for(r ll i=1,j;i<=n;i=j+1)
{
j=((k/i)==0)?n:min(n,k/(k/i)); //结论
ans-=(k/i)*(j-i+1)*(i+j)>>1;//k/i 是值,(j-i+1)*(i+j)/2 等差数列的求和公式,好好理解
}
cout<<ans;
return 0;
}