数论分块:在某个区间内 为一定值,将该值相同的区间分为一块。
对于含有 的求和式子,对于任意一个 i (i <= n),我们需要找到一个最大的 j (i <= j <= n)使得
,这个很好得出,既然我们要对含有 的式子求和,那我们就要找到区间的都含有 。假设 i 是第一次出现满足 要求的下标,那么显然这段区间内都是 的倍数,所以用 n 除以 ,就得到了最大的那个下标。然后每次以为一块,进行分块求和。
证明:
得证:
BZOJ1257:余数之和
给定n和k,求上面式子的值,1 <= n, k <= 10^9。
显然不能通过时间复杂度内算出,我们可以化简一下式子
利用 在区间为定值进行分块,在某一块中,,然后用等差数列求和公式即可算出该区间值。时间复杂度为。
#include<cstdio>
#include<iostream>
using namespace std;
typedef long long ll;
ll n, k;
int main()
{
while(scanf("%lld %lld", &n, &k) == 2) {
ll ans, r;
ans = n*k;
for(ll l = 1; l <= n; l = r+1) {
if(k / l) r = min(n, k/(k/l));
else r = n;
ans -= (k/l)*(l+r)*(r-l+1)/2;
}
printf("%lld\n", ans);
}
return 0;
}