[CQOI2007] 余数求和

Description

\(\sum_{i=1}^n\;k\;mod\;i\)

Solution

先化简式子
\(\sum_{i=1}^n\;k\;mod\;i=\sum_{i=1}^nk-\lfloor{\frac{k}{i}}\rfloor=k\times n-\sum_{i=1}^n\lfloor{\frac{k}{i}}\rfloor\)

用样例打表找规律之后,发现 \(\lfloor{\frac{k}{i}}\rfloor\) 分别在一定的区域内相等。

所以用分块除法来做这题。

首先定义 \(t=\lfloor{\frac{k}{i}}\rfloor\)

\(l\) 来代表我们当前除法块的左边界, \(r\) 来代表右边界,我们让一开始的 \(l=1\) ,因为第一块除法块的开头永远都是从 \(1\) 开始,然后我们可以通过 \(l\) 来求出 \(r\)

t=k/l;
if(!t) break;
r=std::min(k/t,n);

因为我们的定义是 \(t=\lfloor{\frac{k}{i}}\rfloor\)

所以我们可以直接让 \(t=k/l\) 来求出他当前除法块的商,因为连续一块除法块的商都是相等的(不相等就绝对不是同一块),这样我们算出了 \(t\) ,然后就通过 \(t\) 来找 \(l\)

\(t=0\) 时,\(r=n\)

\(t!=0\) 时,\(r=min(\lfloor{\frac{k}{t}}\rfloor,n)\)

解释如下,因为当 \(t=0\) 时,后面那一块肯定都是大于 \(k\) 的那一段,所以我们直接让 \(r=n\) ,算出最后这一大块,当 \(t!=0\) 的时候,我们让 \(r=\lfloor{\frac{k}{t}}\rfloor\),这样可以算出有这个整除的商的最大的一个整数是多少,因为 \(\lfloor{\frac{k}{t}}\rfloor\) 可能会大于 \(n\) ,所以我们加上一个 \(min\) 函数,防止他超过边界。 有了右边界,每一块的和也就好求了

剩下的就是用 \(n\times k\)减去每一块的值就好了

摘自

Code

#include<cstdio>
#include<iostream>
#define int long long

int ans;
int n,k;

signed main(){
	int r;
	scanf("%lld%lld",&n,&k);
	for(int i=1;i<=n;i=r+1){
		int t=k/i;
		if(!t) break;
		r=std::min(k/t,n);
		ans+=t*(i+r)*(r-i+1)/2;
		//printf("i=%lld,ans=%lld\n",i,ans);
	}
	printf("%lld\n",n*k-ans);
	return 0;
}
posted @ 2018-05-11 23:35  YoungNeal  阅读(263)  评论(0编辑  收藏  举报