Label
数论分块
Description
给定正整数n,k(n,k≤109)n,k(n,k\le10^9)n,k(n,k≤109),求∑i=1nk\sum_{i=1}^{n}k∑i=1nk modmodmod iii
Solution
前置引理:
引理1:∀a,b,c∈Z,⌊abc⌋=⌊⌊ab⌋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+,∣{⌊nd⌋∣d∈N+,d≤n}∣≤2n\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⌋,⌊nd⌋d\le\lfloor\sqrt n\rfloor,\lfloor\frac{n}{d}\rfloord≤⌊n⌋,⌊dn⌋至多有n\sqrt nn种取值;而对于d>nd>\sqrt nd>n,此时有⌊nd⌋≤n\lfloor\frac{n}{d}\rfloor\leq\sqrt n⌊dn⌋≤n,最多也只有n\sqrt nn种取值,证毕。
数论分块
数论分块一般用来解决含有⌊ni⌋\lfloor\frac{n}{i}\rfloor⌊in⌋的求和式子。对于任意一个iii,我们需要O(1)O(1)O(1)求出最大的jjj使得⌊ni⌋=⌊nj⌋\lfloor\frac{n}{i}\rfloor=\lfloor\frac{n}{j}\rfloor⌊in⌋=⌊jn⌋。
Problem:求∑i=1n⌊ni⌋\sum_{i=1}^{n}\lfloor\frac{n}{i}\rfloor∑i=1n⌊in⌋
引理333:设⌊ni⌋=k\lfloor\frac{n}{i}\rfloor=k⌊in⌋=k,则max{j∣⌊nj⌋=k}=⌊n⌊ni⌋⌋max\{j|\lfloor\frac{n}{j}\rfloor=k\}=\lfloor\frac{n}{\lfloor\frac{n}{i}\rfloor}\rfloormax{j∣⌊jn⌋=k}=⌊⌊in⌋n⌋
证明:⌊ni⌋=k↔k≤ni<k+1↔nk+1<i≤nk\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
又由于iii为正整数,故i≤nk↔i≤⌊nk⌋=⌊n⌊ni⌋⌋i\leq \frac{n}{k}\leftrightarrow i\leq\lfloor\frac{n}{k}\rfloor=\lfloor\frac{n}{\lfloor\frac{n}{i}\rfloor}\rfloori≤kn↔i≤⌊kn⌋=⌊⌊in⌋n⌋,所以iii的取值上界为⌊n⌊ni⌋⌋\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]分成大约2n2\sqrt n2n块,每一块O(1)O(1)O(1)求和即可。
对于此题
∑i=1nk\sum_{i=1}^{n}k∑i=1nk modmodmod iii=∑i=1n(k−i⌊ki⌋)=nk−∑i=1ni⌊ki⌋=\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=1ni⌊ki⌋\sum_{i=1}^{n}i\lfloor\frac{k}{i}\rfloor∑i=1ni⌊ik⌋,由于分块后每块对应区间内⌊ki⌋\lfloor\frac{k}{i}\rfloor⌊ik⌋值不变,故等差数列求和后乘以⌊ki⌋\lfloor\frac{k}{i}\rfloor⌊ik⌋便是此分块对答案的贡献。
算法时间复杂度O(n)O(\sqrt n)O(n)
拓展:二维数论分块
求∑i=1min(m,n)⌊mi⌋⌊ni⌋\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))
即可(此时划分的块区间内⌊mi⌋,⌊ni⌋\lfloor\frac{m}{i}\rfloor,\lfloor\frac{n}{i}\rfloor⌊im⌋,⌊in⌋值显然不变,最多分成4n4\sqrt n4n块)。
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;
}