数学体操 模运算


概述

求下列式子的值:∑i=1nn mod i.\sum_{i=1}^n n\ mod\ i.i=1nn mod i.

其中,1≤n≤109.1\leq n \leq 10^9.1n109.

----------------------------------------
#思路
我们可以将n mod in\ mod\ in mod i写成n−⌊ni⌋×in-\lfloor \frac{n}{i}\rfloor \times inin×i,那么原式就变成了:Ans=∑i=1nn mod i=∑i=1nn−⌊ni⌋×i=(∑i=1nn)−(∑i=1n⌊ni⌋×i).Ans=\sum_{i=1}^nn\ mod\ i=\sum_{i=1}^nn-\lfloor \frac{n}{i}\rfloor \times i=(\sum_{i=1}^nn)-(\sum_{i=1}^n\lfloor \frac{n}{i}\rfloor \times i).Ans=i=1nn mod i=i=1nnin×i=(i=1nn)(i=1nin×i).

整理一下:Ans=n2−∑i=1n⌊ni⌋×i.Ans = n^2-\sum_{i=1}^n\lfloor \frac{n}{i}\rfloor \times i.Ans=n2i=1nin×i.

那么现在的关键就是求后面那个∑\sum的值了。

我们可以观察一下n=11n=11n=11时,每个iii⌊ni⌋\lfloor \frac{n}{i}\rfloorin值: i:1234567891011\ \quad i:\quad1\quad 2\quad 3\quad 4 \quad 5\quad 6 \quad7 \quad8 \quad9 \quad10\quad11 i:1234567891011⌊ni⌋: 115322111111\lfloor \frac{n}{i}\rfloor:\ 11\quad 5\quad 3\quad 2\quad 2\quad 1\quad 1\quad 1\quad 1\quad 1\quad 1in: 115322111111

观察细致的读者也许发现了,同一个⌊ni⌋\lfloor \frac{n}{i}\rfloorin值总是连续出现的,而且出现的次数似乎也有规律?

是的,令iii的贡献⌊ni⌋=x\lfloor \frac{n}{i}\rfloor =xin=x,那么xxx出现的次数为⌊nx⌋−⌊nx+1⌋\lfloor \frac{n}{x}\rfloor-\lfloor \frac{n}{x+1}\rfloorxnx+1n次。

这个结论可以这么理解:贡献大于等于xxx⌊ni⌋\lfloor \frac{n}{i}\rfloorin一共有⌊nx⌋\lfloor \frac{n}{x}\rfloorxn个,贡献大于xxx⌊ni⌋\lfloor \frac{n}{i}\rfloorin一共有⌊nx+1⌋\lfloor \frac{n}{x+1}\rfloorx+1n个,两者相减即是贡献等于xxx的个数了。

所以,我们可以分块计算贡献。对于⌊ni⌋\lfloor \frac{n}{i}\rfloorin相等的一个块,我们计算∑⌊ni⌋×i\sum \lfloor \frac{n}{i}\rfloor \times iin×i可以提出公因数⌊ni⌋\lfloor \frac{n}{i}\rfloorin,剩下∑i\sum ii是个等差数列,可以用求和公式直接计算。总复杂度均摊O(n).O(\sqrt n).O(n).

----------------------------------------

代码

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#define ll long long
#define For(i,j,k) for(register int i=j; i<=(int)k; ++i)
#define Forr(i,j,k) for(register int i=j; i>=(int)k; --i)
#define INF 0x3f3f3f3f
using namespace std;

ll n, top, v, len, Ans;

int main(){
	scanf("%lld", &n);
	
	top = n;
	Ans = n*n;
	while(top >= 1){
		v = n/top;//计算当前位置的贡献.
		len = n/v - n/(v+1);//计算当前位置贡献出现的次数.
		Ans -= v*(2*top-len+1)*len/2;//更新答案.
		top -= len;//更新当前位置.
	}
	
	printf("%lld", Ans);
	return 0;
}

----------------------------------------

小结

本题重点在于将模运算转化成常见的四则运算,再观察贡献表(姑且这么叫吧)找出每个数的贡献所具有的规律,然后就可以快速计算了。

----------------------------------------

——wrote by miraclejzd.\mathscr ——wrote\ by\ miraclejzd.wrote by miraclejzd.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值