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); }