题目
牛牛以前在老师那里得到了一个正整数数对(x, y), 牛牛忘记他们具体是多少了。
但是牛牛记得老师告诉过他x和y均不大于n, 并且x除以y的余数大于等于k。
牛牛希望你能帮他计算一共有多少个可能的数对。
输入描述:
输入包括两个正整数n,k(1 <= n <= 10^5, 0 <= k <= n - 1)。
输出描述:
对于每个测试用例, 输出一个正整数表示可能的数对数量。
解答
因为x除以y余数要大于等于k,所以y必须是[k-1,n]之间的整数。
为了更好地认识问题,用一个例子观察一下,比如此时x=11,y=4,k=3则
x=1,2,3,4 \quad 5,6,7,8 \quad 9,10,11
因为y=4,所以可以将数据4个一组,发现在每一组中余数的规律为1,2,3,0。因此可以确定每一组符合条件的x有y-k个,而n个数字中总共有n/y个,因此总共的符合条件的数对有(n%y)*(y-k)。
但是在n个数字中,最后一组数字往往不完整,所以需要特殊处理。最后一组数字的长度为n%k。剩下的数字中,前面的k-1(上例的9,10)个除以y余数都是小于k,因此剩下的数字中共有n%k-(k-1)个满足条件的。
分析完毕,代码如下:
#include<iostream>
#include <algorithm>
using namespace std;
int main(){
long long n,k;
cin>>n>>k;
long long count = 0;
long long zero = 0;
if(k==0){
count=n*n;
cout<<count<<endl;
return 0;
}
for(long long y = k+1; y <=n; y++){
count+=(n/y)*(y-k);
count+=max(zero,n%y-k+1);
}
cout<<count<<endl;
return 0;
}
另外,算法核心是在for循环中,对于每一个符合的y,先算出n中以y为长度的每组数字中中符合的x。然后在最后一组数字中获得符合的x。但是如果当k==0时,在最后一组数字获得的x数量将会出错,因此当k==0时直接输出结果。
另外,在计算(n/y)*(y-k)时,由于n的取值最大为
1
0
5
10^5
105,如果用int来存储的话将会溢出。因此用long long来存储各项数据。