Label
数论分块
Description
给定正整数 n , k ( n , k ≤ 1 0 9 ) n,k(n,k\le10^9) n,k(n,k≤109),求 ∑ i = 1 n k \sum_{i=1}^{n}k ∑i=1nk m o d mod mod i i i
Solution
前置引理:
引理1: ∀ a , b , c ∈ Z , ⌊ a b c ⌋ = ⌊ ⌊ a b ⌋ c ⌋ \forall a,b,c\in \Z,\lfloor\frac{a}{bc}\rfloor=\lfloor\frac{\lfloor\frac{a}{b}\rfloor}{c}\rfloor ∀a,b,c∈Z,⌊bca⌋=⌊c⌊ba⌋⌋
(此处没用到,以后推式子会用)
引理2: ∀ n ∈ N + , ∣ { ⌊ n d ⌋ ∣ d ∈ N + , d ≤ n } ∣ ≤ 2 n \forall n\in\N^{+},|\{\lfloor\frac{n}{d}\rfloor|d\in \N^+,d\le n\}| \le2\sqrt n ∀n∈N+,∣{⌊dn⌋∣d∈N+,d≤n}∣≤2n
证明:对于 d ≤ ⌊ n ⌋ , ⌊ n d ⌋ d\le\lfloor\sqrt n\rfloor,\lfloor\frac{n}{d}\rfloor d≤⌊n⌋,⌊dn⌋至多有 n \sqrt n n种取值;而对于 d > n d>\sqrt n d>n,此时有 ⌊ n d ⌋ ≤ n \lfloor\frac{n}{d}\rfloor\leq\sqrt n ⌊dn⌋≤n,最多也只有 n \sqrt n n种取值,证毕。
数论分块
数论分块一般用来解决含有 ⌊ n i ⌋ \lfloor\frac{n}{i}\rfloor ⌊in⌋的求和式子。对于任意一个 i i i,我们需要 O ( 1 ) O(1) O(1)求出最大的 j j j使得 ⌊ n i ⌋ = ⌊ n j ⌋ \lfloor\frac{n}{i}\rfloor=\lfloor\frac{n}{j}\rfloor ⌊in⌋=⌊jn⌋。
Problem:求 ∑ i = 1 n ⌊ n i ⌋ \sum_{i=1}^{n}\lfloor\frac{n}{i}\rfloor ∑i=1n⌊in⌋
引理 3 3 3:设 ⌊ n i ⌋ = k \lfloor\frac{n}{i}\rfloor=k ⌊in⌋=k,则 m a x { j ∣ ⌊ n j ⌋ = k } = ⌊ n ⌊ n i ⌋ ⌋ max\{j|\lfloor\frac{n}{j}\rfloor=k\}=\lfloor\frac{n}{\lfloor\frac{n}{i}\rfloor}\rfloor max{j∣⌊jn⌋=k}=⌊⌊in⌋n⌋
证明: ⌊ n i ⌋ = k ↔ k ≤ n i < k + 1 ↔ n k + 1 < i ≤ n k \lfloor\frac{n}{i}\rfloor=k\leftrightarrow k\leq\frac{n}{i}<k+1\leftrightarrow \frac{n}{k+1}<i\leq\frac{n}{k} ⌊in⌋=k↔k≤in<k+1↔k+1n<i≤kn
又由于 i i i为正整数,故 i ≤ n k ↔ i ≤ ⌊ n k ⌋ = ⌊ n ⌊ n i ⌋ ⌋ i\leq \frac{n}{k}\leftrightarrow i\leq\lfloor\frac{n}{k}\rfloor=\lfloor\frac{n}{\lfloor\frac{n}{i}\rfloor}\rfloor i≤kn↔i≤⌊kn⌋=⌊⌊in⌋n⌋,所以 i i i的取值上界为 ⌊ n ⌊ n i ⌋ ⌋ \lfloor\frac{n}{\lfloor\frac{n}{i}\rfloor}\rfloor ⌊⌊in⌋n⌋。
利用引理2、3,我们可以 O ( n ) O(\sqrt n) O(n)将 [ 1 , n ] [1,n] [1,n]分成大约 2 n 2\sqrt n 2n块,每一块 O ( 1 ) O(1) O(1)求和即可。
对于此题
∑ i = 1 n k \sum_{i=1}^{n}k ∑i=1nk m o d mod mod i i i = ∑ i = 1 n ( k − i ⌊ k i ⌋ ) = n k − ∑ i = 1 n i ⌊ k i ⌋ =\sum_{i=1}^{n}(k-i\lfloor\frac{k}{i}\rfloor)=nk-\sum_{i=1}^{n}i\lfloor\frac{k}{i}\rfloor =∑i=1n(k−i⌊ik⌋)=nk−∑i=1ni⌊ik⌋
对于 ∑ i = 1 n i ⌊ k i ⌋ \sum_{i=1}^{n}i\lfloor\frac{k}{i}\rfloor ∑i=1ni⌊ik⌋,由于分块后每块对应区间内 ⌊ k i ⌋ \lfloor\frac{k}{i}\rfloor ⌊ik⌋值不变,故等差数列求和后乘以 ⌊ k i ⌋ \lfloor\frac{k}{i}\rfloor ⌊ik⌋便是此分块对答案的贡献。
算法时间复杂度 O ( n ) O(\sqrt n) O(n)
拓展:二维数论分块
求 ∑ i = 1 m i n ( m , n ) ⌊ m i ⌋ ⌊ n i ⌋ \sum_{i=1}^{min(m,n)}\lfloor\frac{m}{i}\rfloor\lfloor\frac{n}{i}\rfloor ∑i=1min(m,n)⌊im⌋⌊in⌋。
此时将代码中 r = n/(n/i)
替换成 r = min(n/(n/i), m/(m/i))
即可(此时划分的块区间内
⌊
m
i
⌋
,
⌊
n
i
⌋
\lfloor\frac{m}{i}\rfloor,\lfloor\frac{n}{i}\rfloor
⌊im⌋,⌊in⌋值显然不变,最多分成
4
n
4\sqrt n
4n块)。
Code
#include<cstdio>
#include<iostream>
#define ri register int
#define ll long long
using namespace std;
ll n,k,l,r,ans;
int main()
{
std::ios::sync_with_stdio(false);
cin>>n>>k;
l=1,ans=n*k;
while(l<=n)
{
if(k/l==0) break;
r=k/(k/l);
if(r>n) r=n;
ans-=(k/l)*(r*(r+1)/2-l*(l-1)/2);
l=r+1;//分块时块的划分的移动
}
cout<<ans;
return 0;
}