BZOJ 1257 余数之和

http://www.lydsy.com/JudgeOnline/problem.php?id=1257

题目

输入n,k,求[sum_{i=1}^n kmod i]

$1leqslant n,kleqslant 10^9$

题解

这是一道neerc2005的题目

如果直接算肯定超时

$kmod i$可以写成

[k-leftlfloor frac{k}{i} ight floor imes i]

打表会发现$leftlfloorfrac{k}{i} ight floor$有时候会重复

然后就是构造什么时候重复

需要用到

[leftlfloorfrac{k}{i} ight floorleqslant left(frac{k}{i} ight)]

那么

[leftlfloorfrac{k}{leftlfloorfrac{k}{leftlfloorfrac{k}{i} ight floor} ight floor} ight floorleqslantleftlfloorfrac{k}{leftlfloorfrac{k}{left(frac{k}{i} ight)} ight floor} ight floor=leftlfloorfrac{k}{leftlfloor i ight floor} ight floor=leftlfloorfrac{k}{i} ight floor]

[leftlfloorfrac{k}{leftlfloorfrac{k}{leftlfloorfrac{k}{i} ight floor} ight floor} ight floorgeqslantleftlfloorfrac{k}{left(frac{k}{leftlfloorfrac{k}{i} ight floor} ight)} ight floor=leftlfloorleftlfloorfrac{k}{i} ight floor ight floor=leftlfloorfrac{k}{i} ight floor]

所以

[leftlfloorfrac{k}{leftlfloorfrac{k}{leftlfloorfrac{k}{i} ight floor} ight floor} ight floor=leftlfloorfrac{k}{i} ight floor]

显然中间部分也应该相等,因为若$x<y$,那么

[leftlfloor x ight floorleqslantleftlfloor y ight floor]

这样就可以加速一部分,但是能加速多少呢?

直接打表验证:

int main() {
	ll i=1;
	int cnt=0;
	while(i<int(1e9)) {
		cnt++;
		printf("%10lld", i);
		i=int(1e9)/i;
		i=int(1e9)/i;
		i++;
	}
	printf("
%d
", cnt);
}

得到最坏情况只有63244次循环

那么,可以直接求和了

[sum_{i=1}^n kmod i=nk-sum_{i=1}^n leftlfloorfrac{k}{i} ight floor imes i]

对于每一段相等的,第二项是一个等差数列,可以过时限

虽然不会证明时间复杂度,但是这样可以省很多证明的时间

AC代码

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define REP(i,a,b) for(int i=(a); i<(b); i++)
#define REPE(i,a,b) for(int i=(a); i<=(b); i++)
#define PERE(i,a,b) for(int i=(a); i>=(b); i--)
using namespace std;
typedef long long ll;
int main() {
	int n,k; scanf("%d%d", &n, &k);
	ll i=1, ans=(ll)n*k;
	while(i<=n) {
		if(i>k) {
			break;
		} else {
			int j=k/(k/i);
			if(j>n) j=n;
			ans-=(i+j)*(k/i)*(j-i+1)/2;
			i=j+1;
		}
	}
	printf("%lld
", ans);
}
原文地址:https://www.cnblogs.com/sahdsg/p/12708261.html