LUOGU P2261 [CQOI2007]余数求和(数论分块)

传送门

解题思路

  数论分块,首先将 \(k\%a\) 变成 \(k-a*\left\lfloor\dfrac{k}{a}\right\rfloor\)形式,那么\(\sum\limits_{i=1}^nk\%i=n*k-\sum\limits_{i=1}^ni*\left\lfloor\dfrac{k}{i}\right\rfloor\),这样的话因为\(\left\lfloor\dfrac{k}{i}\right\rfloor\)的取值只有\(O(\sqrt n)\)级别,所以可以每次找到相等值的左端点和右端点,用一次等差数列求和公式即可。

代码

#include<iostream>
#include<cstdio>
#include<cstring>

using namespace std;
typedef long long LL;

int n,k;
LL ans;

int main(){
   scanf("%d%d",&n,&k);ans=(LL)n*k;
   for(int l=1,r;l<=n;l=r+1){
   	if((k/l)!=0) r=min(k/(k/l),n);
   	else r=n;
   	ans-=(LL)(k/l)*(r-l+1)*(l+r)/2;
   }
   cout<<ans;
   return 0;
} 
posted @ 2018-10-15 15:14  Monster_Qi  阅读(158)  评论(0编辑  收藏  举报