这是本人第一篇博客,写的不好请尽力吐槽。
Time Limit: 5 Sec Memory Limit: 128 MB
Submit: 6612 Solved: 3190
[Submit][Status][Discuss]
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
首先,我不知道为什么5s的时限下,暴力为什么过不了。
然后,看书看不懂,网上的博客不清不楚。于是,我又重新看了一遍书……
因为k mod i=k− ⌊ik⌋∗i,所以ans=n*k-∑i=1n ⌊ik⌋∗i。
对于任意x∈ [1,k],设g(x)=⌊k/⌊xk⌋⌋.
因为函数f(x)=k/x(不向下取整)当x∈N+ 时,函数单调递减,g(x)>=⌊k/f(x)⌋=x,故⌊k/ g(x)⌋<=⌊k/x ⌋
同时,⌊k/ g(x)⌋>=⌊k/(k/⌊k/x⌋)⌋(除数小,商就大)=⌊k/k∗⌊k/ x⌋⌋=
⌊k/x ⌋.
所以⌊k/ g(x)⌋=⌊k/x ⌋
把g(x)换元得到⌊k/ ⌊k/⌊ik⌋⌋⌋=⌊k/x ⌋(好丑啊)
又因为f(x)的性质,所以当i∈ [x,⌊k/⌊ik⌋⌋ ]时,f(i)随着i的增大而减小(x恒大于0,反比例函数的性质),那么⌊ f(i)⌋就是非上升函数,因为两端的i,⌊ f(i)⌋值都相等了,对于中间的i,⌊ f(i)⌋也一定相等。
我们就可以把1~n分成若干块,每一块的⌊ k/i⌋都相等,于是就可以用等差数列求和的方法就每一块的值。时间复杂度由O(n)变为O(√n)。
代码如下:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
int main()
{
ll n,k;scanf("%lld%lld",&n,&k);
ll ans=n*k;
for(int i=1,m;i<=n;i=m+1)
{
k/i?m=min(n,k/(k/i)):m=n;
ans-=((k/i)*(i+m)*(m-i+1))/2;
}
printf("%lld
",ans);
return 0;
}