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。
Output
输出仅一行,即j(n, k)。
Sample Input
5 3
Sample Output
7
Hint
50%的数据满足:1<=n, k<=1000 100%的数据满足:1<=n ,k<=10^9
nmodi=n−i×⌊ni⌋
∑ni=1Kmod i
=∑ni=1(K−⌊K/i⌋∗i)
=nK−∑ni=1⌊K/i⌋∗i
打这么一个表。然后窝门就可以发现这是单调递减的诶。。所以我们二分的查找连续相等的段就好了。。
//for(int i=1;i<30;i++)cout<<12/i<< endl;
#include<bits/stdc++.h>
using namespace std;
#define LL long long
int n,k;
int find_last(int x){
int l=x,r=n;
int temp;
while(l<=r){
int mid=(l+r)/2;
if((k/x)>(k/mid)) r=mid-1;
else{
temp=mid;
l=mid+1;
}
}
return temp;
}
int main() {
while(scanf("%d %d",&n,&k)!=EOF){
LL ans=1LL*n*k;
for(int i=1;i<=n;){
int last=find_last(i);
ans-=1LL*(k/i)*(i+last)*(last-i+1)/2;
i=last+1;
}
printf("%lld\n",ans);
}
return 0;
}
这一份代码直接j=min(n,k/(k/i));就干了我一个二分查找的活。。还没能理解这是为啥。。先贴上,窝再仔细想想。。
/*
int main() {
LL n,k;
while(scanf("%lld %lld",&n,&k)!=EOF){
LL ans=n*k;
n=min(n,k);
LL j=0;
for(int i=1;i<=n;i=j+1){
j=min(n,k/(k/i));
ans-=(k/i)*(i+j)*(j-i+1)/2;
}
printf("%lld\n",ans);
}
return 0;
}
*/