首先我们假设存在
x
x
x满足
a
,
b
∈
[
l
,
r
]
,
g
c
d
(
a
,
b
)
=
x
a,b\in[l,r],gcd(a,b)=x
a,b∈[l,r],gcd(a,b)=x
那么肯定
g
c
d
(
⌊
a
/
x
⌋
,
⌊
b
/
x
⌋
)
=
1
就是互质
gcd(\lfloor a/x \rfloor, \lfloor b/x \rfloor)=1就是互质
gcd(⌊a/x⌋,⌊b/x⌋)=1就是互质
假设
a
<
b
a<b
a<b
那么
b
最小可以取
=
(
⌊
a
/
x
⌋
+
1
)
∗
x
b最小可以取 = (\lfloor a/x \rfloor +1)*x
b最小可以取=(⌊a/x⌋+1)∗x 因为
(
⌊
a
/
x
⌋
+
1
)
和
⌊
a
/
x
⌋
(\lfloor a/x \rfloor +1) 和 \lfloor a/x \rfloor
(⌊a/x⌋+1)和⌊a/x⌋肯定互质
那么我们可以贪心的找两个最小的倍数,就是
k
x
和
(
k
+
1
)
x
∈
[
l
,
r
]
kx和(k+1)x\in[l,r]
kx和(k+1)x∈[l,r]
那么分类讨论一下
如果
x
∈
[
l
,
r
]
x\in[l,r]
x∈[l,r]那么只要
x
,
2
x
∈
[
l
,
r
]
x,2x\in[l,r]
x,2x∈[l,r]即可
如果
x
<
l
x<l
x<l那么就是公式
k
x
≥
l
&
&
(
k
+
1
)
x
≤
r
kx\geq l \&\&(k+1)x\leq r
kx≥l&&(k+1)x≤r
那么根据贪心对于同一个
x
x
x,最小的
k
=
⌈
l
/
x
⌉
k=\lceil l/x \rceil
k=⌈l/x⌉,那么
x
≤
r
/
(
⌈
l
/
x
⌉
+
1
)
x\leq r/(\lceil l/x \rceil+1)
x≤r/(⌈l/x⌉+1)
看到上面的向上取整,我们可以想到算法数论分块,因为对于同一个范围内的
x
x
x,这个最小的k值都是固定的
现在把
⌈
l
/
x
⌉
=
⌊
(
l
−
1
)
/
x
+
1
⌋
\lceil l/x \rceil = \lfloor (l-1)/x+1\rfloor
⌈l/x⌉=⌊(l−1)/x+1⌋就可以带入数论分块了
x
≤
r
/
(
⌊
(
l
−
1
)
/
x
+
1
⌋
+
1
)
x\leq r/(\lfloor (l-1)/x+1\rfloor+1)
x≤r/(⌊(l−1)/x+1⌋+1)
代码实现
#include<iostream>#include<cstring>#include<cmath>#include<vector>#include<algorithm>usingnamespace std;constint maxn =3005;typedeflonglong ll;typedef pair<int,int> PII;typedef pair<ll,ll> PLL;const ll mod =998244353;
vector<int> arr;
ll sum, pre;intmain(){// freopen("1.txt","r",stdin);int T;scanf("%d",&T);while(T --){
ll l,r;scanf("%lld%lld",&l,&r);
ll ans =max(0ll,r/2-l+1);for(ll L =1, R =1; L < l; L = R +1){
ll num =(l-1)/L;
R =min((l-1)/num,l-1);// 数论分块的右边界
ll now = r/(num+2);// 上面不等式的右边// printf("now = %lld ans = %lld L = %lld R = %lld\n",now,ans,L,R);if(now >= L) ans +=(min(now,R)-L+1);}printf("%lld\n",ans);}return0;}