题目大意
求 ∑ni=1k mod i ,n,k<=1013
解题分析
这道题的被除数不变,然后除数是依次加1,直觉就是余数是有规律的,事实上也确实有规律。
令 a=k/i (整除运算),则 k mod i=k−a∗i
那么对于接下来的i+1,假设 a=k/(i+1) (i+1和i被k除的整数部分相同),有 k mod (i+1)=k−a∗(i+1)=k−a∗i−a=k mod i−a
然后对于i+2,如果被k除的整数部分与i+1相同,那么很明显 k mod (i+2)=k mod i−2∗a
这里就会发现,如果对于一个区间[i,j],他们被k除的商的整数部分a相同,那么他们的余数可以构成一个公差为a的等差数列,所以这样的话可以枚举整数部分a,然后找出被k出后整数为a的最小值和最大值,并直接求出他俩的余数,然后套进等差数列公式就行了。
注意,在1-sqrt(n)范围内的商a是各不相同的,所以这里有分块的思想:1-sqrt(n)直接求,然后a范围也是1-sqrt(n),套等差数列(这道题算数论嘛???),大于k的直接ans+=k。
时间:O( sqrt(n) ); 空间:O(1);
#include<cmath>
#include<cstdio>
#define LL long long
LL n,m,ans; int k;
using namespace std;
int main()
{
freopen("remainders.in","r",stdin);
freopen("remainders.out","w",stdout);
scanf("%lld%lld",&m,&n); k=sqrt(n); ans=0;
if (m>n) {ans+=(m-n)*n; m=n;}
for (int i=2;i<=k&&i<=m;i++) ans+=n%i;
for (int i=1;i<=k&&m>k;i++){
LL L=n/(i+1)+1,R=n/i,tema,temb;
if (L<k+1) L=k+1; if (R>m) R=m; if (L>R) continue;
tema=n%L; temb=n%R; ans+=(tema+temb)*(R-L+1)/2;
}
printf("%lld",ans);
return 0;
}