Acwing199. 余数之和(数学+思维)

给出正整数n和k,计算j(n, k)=k mod 1 + k mod 2 + k mod 3 + … + k mod n的值。

例如j(5, 3)=3 mod 1 + 3 mod 2 + 3 mod 3 + 3 mod 4 + 3 mod 5=0+1+0+3+3=7。

输入格式

输入仅一行,包含两个整数n, k。

输出格式

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

数据范围

1n,k109

输入样例:

5 3

输出样例:

7

思路:看了大神的代码才学会的,方法是分块:
\(j(n,k) = \displaystyle\sum_{i=1}^n(k- \lfloor \frac{k}{i} \rfloor * i) = n*k - \sum_{i=1}^n(\lfloor \frac{k}{i} \rfloor * i)\)
然后我们根据式子可以发现,难点在于\(\lfloor \frac{k}{i} \rfloor\) 的求法,可以看出来\(\lfloor \frac{k}{i} \rfloor\)的值在i变化时可能不会发生改变,所以我们思考是否能够通过求\(\lfloor \frac{k}{i} \rfloor\) 的变化范围进而求值。想到这一步必须先证明\(\lfloor \frac{k}{i} \rfloor\) 中的值的确是很有限的,与\(n\)不在一个量级上,事实证明确实是这样的,考虑\(i\)的取值从\(1-\sqrt k\)的情况,因为该段有\(\sqrt k\)个取值,所以在该段的\(\lfloor \frac{k}{i} \rfloor\)最多有\(\sqrt k\)个取值,然后考虑\(\sqrt k-k\)的情况,观察\(\lfloor \frac{k}{i} \rfloor\)发现当\(i\)\(\sqrt k->k\)\(\lfloor \frac{k}{i} \rfloor \leq \sqrt k\)那就证明了在\(\sqrt k->k\)段上,也最多仅有\(\sqrt k\)个取值;
然后我们现在就是求对于\(\lfloor \frac{k}{i} \rfloor\)的每一个取值的上下界,设一个取值的下界是\(x\)那么上界会是什么呢?
\(a*b = k\)(左边不一定是整数)观察到我们如果想让\(b\)的取值不发生变化,那么我们取\(\lfloor b \rfloor\)能得到最大的\(a\),这里的思路也是这样,上界取\(\lfloor k/\lfloor k/x \rfloor \rfloor\)这里\(\lfloor k/b \rfloor\)就代表这个\(\lfloor b \rfloor\)的取值;
随后再加一个等差数列求和公式;
\(Code:\)


/*************************************************************************
    > File Name: Acwing.cpp
# Author: Badwoman
# mail: 1194446133@qq.com
    > Created Time: 2020年12月21日 星期一 10时41分06秒
 ************************************************************************/

#include<set>
#include<iostream>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<map>
#include<algorithm>
#include<vector>
#include<queue>
#include<stack>
#define ll long long
#define ull unsigned long long
#define pb push_back
#define mp make_pair
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define bep(i,a,b) for(int i=a;i>=b;--i)
#define lowbit(x) (x&(-x))
using namespace std;
ll n,k;
void solve(){
	scanf("%lld%lld",&n,&k);
	ll ans = n*k,r;
	for(ll l=1;l<=n;l = r+1){
		if(k/l == 0)break;
		r = min(n,k/(k/l));
		ll p = k/l;
		ans -= p*(r-l+1)*(l+r)/2;
	}
	printf("%lld\n",ans);
}
int main(){
	solve();
	return 0;
}

posted @ 2020-12-21 11:29  xiaodangao  阅读(133)  评论(0)    收藏  举报