题目描述
牛牛以前在老师那里得到了一个正整数数对(x, y), 牛牛忘记他们具体是多少了。
但是牛牛记得老师告诉过他x和y均不大于n, 并且x除以y的余数大于等于k。
牛牛希望你能帮他计算一共有多少个可能的数对。
输入描述:
输入包括两个正整数n,k(1 <= n <= 10^5, 0 <= k <= n - 1)。
输出描述:
对于每个测试用例, 输出一个正整数表示可能的数对数量。
输入
5 2
输出
7
说明
满足条件的数对有(2,3),(2,4),(2,5),(3,4),(3,5),(4,5),(5,3)
暴力嵌套两重循环,复杂度太高,105的数据范围肯定是过不去,找规律把前面的数比后面的数小的部分给先算出来,只循环后面数比前面数小的情况,试一试,时间也过不去,那只能从数学上找一找规律了;
首先说这个余数,假设这个数对是(x,y);那么要保证x%y >= k 那么必然 y要大于等于 k + 1 ;
下面对每一个确定的y,来看在1-n范围内的 x。在这个范围内开始取余数,当然 在范围足够大的情况下,余数肯定是有规律的循环出现的(1,2,3, … , y-1 ,0);
那么他会这么循环多少次呢?他会循环(n / y)次;每次循环有多少符合条件的呢?会有(y - k)个符合条件(因为要求的是 x % y >= k, 就是说余数等于k的是包含在内的,我们把0看作是每次余数循环的第一个,这样如果k是2,我们减去k就是减去了余数是0, 1这两个不符合条件的)
然后再看还可能会有不够一次循环的情况出现,那么不够一次循环,他剩下了多少个呢?剩下了(n % k)个,有多少个不符合条件的呢,有(k - 1)个,刚才是把0放到最上面计算了,但是现在没有那个0了,所以少了一个
代码如下:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int main()
{
int n, k;
long long ans = 0;
cin >> n >> k;
if(k == 0){
cout << 1LL * n * n << endl;
return 0;
}
for(int i = k + 1; i <= n; i ++ )
{
ans += (n / i) * (i - k);
if(n % i >= k) ans += n % i - k + 1;
}
cout << ans << endl;
return 0;
}