P2261 [CQOI2007]余数求和 - 数论分块

这道题有着一个转化思想
\(k \bmod i \Leftrightarrow k - i * \lfloor\frac{k}{i}\rfloor\)
所以有\(ans = \sum_i^n (k - i * \lfloor\frac{k}{i}\rfloor) =n*k - \sum_i^n(i*\lfloor\frac{k}{i}\rfloor)\)
注意到\(\lfloor\frac{k}{i}\rfloor\)有许多其实是相同的
假设这些相同的数是x,设\(l\)为第一次出现x的i,\(x = \lfloor\frac{k}{l}\rfloor\)\(r\)是x的右端点,可以发现\(r = \lfloor\frac{k}{x}\rfloor\)(放缩几下可以证明出来,证明不出来背下来也行。。。),于是便可以得到一个跳来跳去的枚举,复杂度是\(O(\sqrt{n})\)
注意r不能跳到n外面了不然答案会算错!

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
#include <cmath>
using namespace std;
#define debug(x) cerr << #x << "=" << x << endl;
const int MAXN = 100000 + 10;
const int INF = 1 << 30;
typedef long long ll;
ll n,ans,r,k,now;
int main() {
	scanf("%lld%lld", &n, &k);
	ans = n * k;
	for(int l=1; l<=n; l=r+1) {
		ll x = k / l;
		if(x == 0) break;
		r = min(k / x, n);
		ll temp = (l + r) * (r - l + 1) / 2;
		ans -= x * temp;
	} 
	printf("%lld\n", ans);
	return 0;
}
posted @ 2018-10-30 21:22  Zolrk  阅读(101)  评论(0编辑  收藏  举报