余数求和(数学题)
题目描述
给出正整数n和k,计算G(n, k)=k mod 1 + k mod 2 + k mod 3 + … + k mod n的值,其中k mod i表示k除以i的余数。例如G(10, 5)=5 mod 1 + 5 mod 2 + 5 mod 3 + 5 mod 4 + 5 mod 5 …… + 5 mod 10=0+1+2+1+0+5+5+5+5+5=29
输入输出格式
输入格式:
两个整数n k
输出格式:
答案
输入输出样例
输入样例#1:
10 5
输出样例#1:
29
说明
30%: n,k <= 1000
60%: n,k <= 10^6
100% n,k <= 10^9
题解:
根据题目要求写出
a
n
s
=
∑
i
=
1
n
k
m
o
d
i
ans=\sum_{i=1}^{n}k \ mod \ i
ans=i=1∑nk mod i
因为a mod b 可以表示a-b*⌊a/b⌋
那么
a
n
s
=
∑
i
=
1
n
k
−
i
∗
⌊
k
/
l
⌋
=
n
∗
k
−
∑
i
=
1
n
i
∗
⌊
k
/
l
⌋
ans=\sum_{i=1}^{n}k-i*⌊k/l⌋=n*k-\sum_{i=1}^ni*⌊k/l⌋
ans=i=1∑nk−i∗⌊k/l⌋=n∗k−i=1∑ni∗⌊k/l⌋
⌊k/i⌋这时就可以用除法分块来做,可以参考下https://blog.youkuaiyun.com/healer66/article/details/82561234
我们用样例来打表找规律,发现分别在一定的区域内相等
可见⌊k/t⌋分成了 p 块,我们只需要计算 n×k 减去每一块的和即可。
首先枚举块的左边界 l,并根据左边界和 k 计算出右边界 r。
令 t =⌊k/t⌋,分两种情况讨论
-
t≠0,则 r = min(⌊k/t⌋,n);
-
t=0,则 r = n。
对于⌊k/i⌋相同的一部分,可以用等差数列求和公式来求
假设在相同的一块内⌊k/i⌋=x,把 x 提出来那一块的答案就是x∗(i+i+1+⋯)
里面是差为1的等差数列,所以就可以用等差数列求和公式
代码:
#include<bits/stdc++.h>
using namespace std;
int main()
{
long long n, k;
cin >> n >> k;
long long ans = n * k;
for(long long l = 1, r; l <= n; l = r+1) {
if(k / l == 0)
r = n;
else {
r = min(n, k/(k/l));
}
ans -= (k/l)*(r-l+1)*(l+r) / 2;
}
cout << ans << endl;
return 0;
}