题意
给定n和k,求
思路
这一题求的是余数,观察余数是怎么来的:
那么
则原始可以化为
把k提出来:
则可以考虑对其中的进行整除分块,计算同一分块对答案的贡献:对于
相同的
,将其归到一块统一处理,从而达到减小时间复杂度的目的。
拿举例如图为
与
的关系:
众所周知,在分块中,是通过双指针l和r实现分块的截取。
对左右指针l和r的计算:对于有序数组,让
为分块的左边界,那么分块的单个值为
,那么右边界就是值为
的最大下标,即寻找满足
的
,即:
下一次截取令即可。
得知l和r怎么计算后,就要将中的
算出来。观察双指针运行中的原理如图:
对于时的
?那不就是等差数列求和吗!
那么对于每个分块,其对答案的贡献为!
还要注意,因为分块的单个值出现了等于0的情况,所以计算右端点时要特判,否则会报错!
具体细节见代码。
代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll z=1e6+9;
void fastread()
{
ios::sync_with_stdio(0);
}
ll n,k,ans;
int main()
{
fastread();
cin>>n>>k;
ans=n*k;
for(ll l=1,r;l<=n;l=r+1)
{
if(k<l)r=n;//k/l已经全为0
else r=min(n,k/(k/l));
ans-=(k/l)*(l+r)*(r-l+1)/2;
//当前块*(首项+末项)*项数/2
}
cout<<ans;
return 0;
}