折跃坐标:https://codeforces.com/contest/1485/problem/C
题面:
题目大意:
(下文中
a
b
\frac ab
ba均为向下取整)
给你一个x,y (1 ≤ x, y ≤ 10e9)
问有多少个(a,b)满足
a
b
=
a
m
o
d
b
(
1
≤
a
≤
x
,
1
≤
b
≤
y
)
\frac ab = a\quad mod \quad b \quad (1 ≤ a ≤ x,1 ≤ b ≤ y)
ba=amodb(1≤a≤x,1≤b≤y)
数学思路:
设
a
b
=
k
\frac ab=k\quad
ba=k,
a
m
o
d
b
=
m
a\quad mod \quad b = m
amodb=m
得
k
∗
b
+
m
=
a
k*b+m=a
k∗b+m=a, 其中
k
=
m
k = m
k=m
整理得到
k
∗
(
b
+
1
)
=
a
(
b
>
k
)
k*(b+1)=a\quad(b>k)
k∗(b+1)=a(b>k)
由此,我们的任务转变为找到对于每个b 有多少个k满足
k
∗
(
b
+
1
)
=
a
(
b
>
k
)
k*(b+1)=a\quad(b>k)
k∗(b+1)=a(b>k)
因为有
1
≤
a
≤
x
a
n
d
k
<
b
1 ≤ a ≤ x \quad and \quad k < b
1≤a≤xandk<b
可以得到
k
=
m
i
n
(
b
−
1
,
x
b
+
1
)
k = min(b-1,\frac{x}{b+1})
k=min(b−1,b+1x)
接下来,我们希望知道一个关于k的分段函数
b
−
1
<
x
b
+
1
b-1 <\frac{x}{b+1}
b−1<b+1x
(
b
+
1
)
∗
(
b
−
1
)
<
x
(b+1)*(b-1)<x
(b+1)∗(b−1)<x
b
2
−
1
<
x
b^2 -1 < x
b2−1<x
b
2
<
x
+
1
b^2 < x + 1
b2<x+1
b
<
x
+
1
b < \sqrt{x+1}
b<x+1
所以
k
=
b
−
1
(
b
<
x
+
1
)
k = b-1\quad(b < \sqrt{x+1})
k=b−1(b<x+1)
k
=
x
b
+
1
(
b
>
x
+
1
)
k = \frac{x}{b+1}\quad(b > \sqrt{x+1})
k=b+1x(b>x+1)
对于
(
b
<
x
+
1
)
(b < \sqrt{x+1})
(b<x+1)的部分,因为比较少,可以直接枚举,也可以直接用等差数列公式求和
对于
(
b
>
x
+
1
)
(b > \sqrt{x+1})
(b>x+1)的部分,我们则需要用整除分块的知识解决
关于整除分块,对于这道题,我们只需要简单地知道,
在
n
i
,
n
i
+
1
.
.
.
.
.
.
\frac ni,\frac{n}{i+1}......
in,i+1n......这样的式子中,最大的,满足
n
i
=
n
j
\frac ni = \frac nj
in=jn的
j
j
j =
n
n
i
\frac{n}{\frac ni}
inn
对于连续的
n
i
,
n
i
+
1
.
.
.
.
.
.
n
j
\frac ni,\frac{n}{i+1}......\frac nj
in,i+1n......jn的和 等同于
(
j
−
i
+
1
)
∗
n
i
(j-i+1)*\frac ni
(j−i+1)∗in
ac代码:
#include <iostream>
#include <queue>
#include <stack>
#include <algorithm>
#include <vector>
#include <string>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <climits>
#define Buff std::ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define ll long long
#define inf LONG_LONG_MAX
#define Inf INT_MAX
using namespace std;
const int Maxn = 1e7 + 10;
const ll Mod = 1e9 + 7;
ll x, y;
ll ans;
int t;
int main()
{
Buff;
cin >> t;
while (t--)
{
ans = 0;
cin >> x >> y;
for (ll b = 2; b <= min(y, (ll)sqrt(x + 1)); b++)
ans += b - 1;
ll l, r;
for (l = sqrt(x + 1) + 1; l <= min(x, y); l = r + 1)
{
if (x / (l + 1) <= 0)
break;
r = min(y, min(x, x / (x / (l + 1))-1));
//这里-1的原因是:除的是l+1而不是l
ans += (r - l + 1) * (x / (l + 1));
}
cout << ans << endl;
}
return 0;
}