CQOI2007 余数之和

Time Limit: 5 Sec Memory Limit: 128 MB

Description

给出正整数n和k,计算j(n, k)=k mod 1 + k mod 2 + k mod 3 + … + k mod n的值
其中k mod i表示k除以i的余数。
例如j(5, 3)=3 mod 1 + 3 mod 2 + 3 mod 3 + 3 mod 4 + 3 mod 5=0+1+0+3+3=7

Input

输入仅一行,包含两个整数n, k。
1<=n ,k<=10^9

Output

输出仅一行,即j(n, k)。

Sample Input

5 3

Sample Output

7

简要题解

我们可以把原式数学化一下:求\(\sum \limits_{i=1}^n k \mod i\)
我们可以发现

\[\begin{align*} \text{原式}&=\sum \limits_{i=1}^n k \mod i\\ &=\sum \limits_{i=1}^n k- \lfloor \frac ki \rfloor \cdot i\\ &=nk - \sum \limits_{i=1}^n \lfloor \frac ki \rfloor \cdot i \end{align*} \]

显然,只要\(\lfloor \frac ki \rfloor\)的值在一段段i的范围内是一样的。我们的任务就是要求出每一段这样的范围。我们令\(f(x)=\lfloor \frac kx \rfloor \qquad g(x)=\lfloor \frac k{\lfloor \frac kx \rfloor} \rfloor\),那么其实直觉就可以告诉我们\(g(x)\)就可以表示f值=\(\lfloor \frac kx \rfloor\)的最大的数。然而数学毕竟是一门严谨的科学,我们可能需要来证明一下。
显然\(\lfloor \frac kx \rfloor \leq \frac kx\),那么\(g(x)=\lfloor \frac k{\lfloor \frac kx \rfloor} \rfloor \geq \lfloor \frac k{\frac kx } \rfloor = x \text{即} g(x) \geq x\)。所以有\(\lfloor \frac k{g(x)} \rfloor \leq \lfloor \frac kx \rfloor\)
同时,\(\lfloor \frac k{g(x)} \rfloor = \lfloor \frac k{\lfloor \frac k{\lfloor \frac kx \rfloor} \rfloor} \rfloor \geq \lfloor \frac k{ \frac k{\lfloor \frac kx \rfloor} } \rfloor = \lfloor \frac kx \rfloor\),即\(\lfloor \frac k{g(x)} \rfloor \geq \lfloor \frac kx \rfloor\)\(\lfloor \frac k{g(x)} \rfloor \leq \lfloor \frac kx \rfloor\),所以\(\lfloor \frac k{g(x)} \rfloor = \lfloor \frac kx \rfloor\)
所以\(\forall i \in [x,\lfloor \frac k{\lfloor \frac kx \rfloor} \rfloor]\)\(\lfloor \frac ki \rfloor\)的值都相等!其实之前的猜想的“最大”是很显然的,也没必要再去证一遍了,就算不是最大的,也不影响我们的这个程序。
下面我们就有了一个算法:统计\([1,g(1)]\)的区间里的\(\lfloor \frac ki \rfloor \cdot i\)的和,既然\(\lfloor \frac ki \rfloor\)都一样,那就用等差数列求和公式来算一下即可。然后在从\(g(1)+1\)\(g(g(1)+1)\)这段区间再如此统计……重复上述步骤,直到\(i>k\),此时\(\lfloor \frac ki \rfloor\)一定等于0,直接令g(i)=n,统计i..n即可。
下面我们算一下时间复杂度。这个时间复杂度,应该等于\(\lfloor \frac ki \rfloor\)有多少个不同的取值是一样的。当\(i \leq \sqrt k\)时,i只有\(\sqrt k\)中取值,所以\(\lfloor \frac ki \rfloor\)也最多只有\(\sqrt k\)种取值。当\(i > \sqrt k\)时,\(\lfloor \frac ki \rfloor < \sqrt k\),所以\(\lfloor \frac ki \rfloor\)也最多只有\(\sqrt k\)种取值,所以\(\lfloor \frac ki \rfloor\)一共最多\(2 \sqrt k\)种取值。所以该算法的之间复杂度为\(O(\sqrt k)\)

代码

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;

int n,k;ll ans;

int main(){
	scanf("%d%d",&n,&k);ans=1ll*n*k;
	for(register int i=1,g;i<=n;i=g+1){
		if(k/i!=0)g=min(n,k/(k/i));else g=n;//错误笔记:如果k/i==0即k<i的话,k/(k/i)会炸掉,所以要特判一下。 
		ans-=(ll)(k/i)*(i+g)*(g-i+1)/2;
	}
	printf("%lld\n",ans);
}
posted @ 2018-06-30 09:55  hankeke303  阅读(220)  评论(0编辑  收藏  举报