前两天肝了整整两天的FFT,博客暂咕
今天打算先肝个莫队,于是复习一下整除分块
题面:
给出
n
,
k
(
1
≤
n
,
k
≤
1
0
9
)
n,k(1\le n,k\le 10^9)
n,k(1≤n,k≤109),求
∑
i
=
1
n
k
m
o
d
i
\large\sum\limits_{i=1}^{n}k\mod i
i=1∑nkmodi
推一波公式:
∑
i
=
1
n
k
m
o
d
i
=
∑
i
=
1
n
k
−
i
∗
⌊
k
i
⌋
=
n
k
−
∑
i
=
1
n
i
∗
⌊
k
i
⌋
\begin{aligned} &\sum\limits_{i=1}^{n}k\mod i\\ =&\sum\limits_{i=1}^{n}k-i*\lfloor\frac{k}{i}\rfloor\\ =&nk-\sum\limits_{i=1}^{n}i*\lfloor\frac{k}{i}\rfloor\\ \end{aligned}
==i=1∑nkmodii=1∑nk−i∗⌊ik⌋nk−i=1∑ni∗⌊ik⌋
推到这里,观察一下
⌊
k
i
⌋
\lfloor\frac{k}{i}\rfloor
⌊ik⌋,发现:到了后面
i
i
i大的时候
⌊
k
i
⌋
\lfloor\frac{k}{i}\rfloor
⌊ik⌋可能会保持不变!
重点来看
⌊
k
i
⌋
\lfloor\frac{k}{i}\rfloor
⌊ik⌋会在什么区间内保持不变:
设
⌊
k
i
⌋
=
⌊
k
j
⌋
=
q
(
i
<
j
)
\lfloor\frac{k}{i}\rfloor=\lfloor\frac{k}{j}\rfloor=q~(i<j)
⌊ik⌋=⌊jk⌋=q (i<j)
则有
q
i
+
x
=
q
j
+
y
=
k
(
0
≤
x
<
i
,
0
≤
y
<
j
)
qi+x=qj+y=k~(0\le x<i,0\le y<j)
qi+x=qj+y=k (0≤x<i,0≤y<j)
最极端的情况便是
y
=
0
y=0
y=0
则
q
i
+
x
=
q
j
=
k
qi+x=qj=k
qi+x=qj=k
肉眼可见
j
=
k
q
j=\frac{k}{q}
j=qk
考虑到可能
q
∤
j
q\nmid j
q∤j
所以
j
=
⌊
k
q
⌋
j=\lfloor\frac{k}{q}\rfloor
j=⌊qk⌋
对于每一个
x
x
x,它所在的
⌊
k
i
⌋
\lfloor\frac{k}{i}\rfloor
⌊ik⌋区间上界就是
k
⌊
k
x
⌋
\frac{k}{\lfloor\frac{k}{x}\rfloor}
⌊xk⌋k
这样就可以通过等差数列对每一块的
i
∗
⌊
k
i
⌋
i*\lfloor\frac {k}{i}\rfloor
i∗⌊ik⌋进行计算了
每块计算公式:
(
l
+
r
)
∗
(
r
−
l
+
1
)
2
∗
(
k
/
l
)
\frac{(l+r)*(r-l+1)}{2}*(k/l)
2(l+r)∗(r−l+1)∗(k/l)
肉眼可见初始块一定是
[
1
,
1
]
[1,1]
[1,1]
递推式:
r
=
⌊
k
⌊
k
l
⌋
⌋
,
l
=
r
+
1
r=\lfloor\frac{k}{\lfloor\frac{k}{l}\rfloor}\rfloor,l=r+1
r=⌊⌊lk⌋k⌋,l=r+1
有一个细节:
如果
l
>
k
l>k
l>k,那么
⌊
k
i
⌋
=
0
\lfloor\frac{k}{i}\rfloor=0
⌊ik⌋=0,会导致除以零
由此我们要加一个特判
#include<cstdio>
using namespace std;
inline int min(const int a,const int b)
{return a<b?a:b;}
int main()
{
int n,k;
scanf("%d%d",&n,&k);
long long ans=0;
for(int l=1,r=1;l<=n;l=r+1,r=k>l?min(n,k/(k/l)):n)
ans+=1ll*(l+r)*(r-l+1)/2*(k/l);
printf("%lld",1ll*n*k-ans);
return 0;
}
这就是整除分块的一种