Description
求 (sum_{i=1}^n;k;mod;i)
Solution
先化简式子
(sum_{i=1}^n;k;mod;i=sum_{i=1}^nk-lfloor{frac{k}{i}}
floor=k imes n-sum_{i=1}^nlfloor{frac{k}{i}}
floor)
用样例打表找规律之后,发现 (lfloor{frac{k}{i}} floor) 分别在一定的区域内相等。
所以用分块除法来做这题。
首先定义 (t=lfloor{frac{k}{i}} floor)
用 (l) 来代表我们当前除法块的左边界, (r) 来代表右边界,我们让一开始的 (l=1) ,因为第一块除法块的开头永远都是从 (1) 开始,然后我们可以通过 (l) 来求出 (r) 。
t=k/l;
if(!t) break;
r=std::min(k/t,n);
因为我们的定义是 (t=lfloor{frac{k}{i}} floor)
所以我们可以直接让 (t=k/l) 来求出他当前除法块的商,因为连续一块除法块的商都是相等的(不相等就绝对不是同一块),这样我们算出了 (t) ,然后就通过 (t) 来找 (l)
当 (t=0) 时,(r=n)。
当 (t!=0) 时,(r=min(lfloor{frac{k}{t}} floor,n))
解释如下,因为当 (t=0) 时,后面那一块肯定都是大于 (k) 的那一段,所以我们直接让 (r=n) ,算出最后这一大块,当 (t!=0) 的时候,我们让 (r=lfloor{frac{k}{t}} floor),这样可以算出有这个整除的商的最大的一个整数是多少,因为 (lfloor{frac{k}{t}} floor) 可能会大于 (n) ,所以我们加上一个 (min) 函数,防止他超过边界。 有了右边界,每一块的和也就好求了
剩下的就是用 (n imes k)减去每一块的值就好了
Code
#include<cstdio>
#include<iostream>
#define int long long
int ans;
int n,k;
signed main(){
int r;
scanf("%lld%lld",&n,&k);
for(int i=1;i<=n;i=r+1){
int t=k/i;
if(!t) break;
r=std::min(k/t,n);
ans+=t*(i+r)*(r-i+1)/2;
//printf("i=%lld,ans=%lld
",i,ans);
}
printf("%lld
",n*k-ans);
return 0;
}