Codeforces 1485C - Floor and Mod (分块、数学)

Codeforces Round #701 (Div. 2) C. Floor and Mod


题意

给定 x , y x,y x,y,询问当 1 ≤ a ≤ x ,   1 ≤ b ≤ y 1\le a\le x,\ 1\le b\le y 1ax, 1by时, ⌊ a b ⌋ = a   m o d   b \lfloor \frac a b \rfloor=a\ mod\ b ba=a mod b的对数

限制

1 ≤ x , y ≤ 1 0 9 1\le x,y\le 10^9 1x,y109




思路

(想法有很多种,本文主要通过分块求解)

(并没有那么难,但为什么总是往难的方向想呢……)

读懂题意后如果用公式化简

根据 a   m o d   b = a − ⌊ a b ⌋ ∗ b a\ mod\ b=a-\lfloor \frac a b \rfloor*b a mod b=abab,最多只能够化到 a = ( b + 1 ) ∗ ⌊ a b ⌋ a=(b+1)*\lfloor \frac a b \rfloor a=(b+1)ba

可得 a b + 1 = ⌊ a b ⌋ \frac a {b+1}=\lfloor \frac a b \rfloor b+1a=ba

明显, b + 1 b+1 b+1一定是 a a a的因子

(然后就想不到其他规律了)


那么我们枚举 b b b,再枚举 b + 1 b+1 b+1的倍数进行打表

Codeforces 1485C - Floor and Mod (分块、数学)_第1张图片

得到规律:

对于任意大于 2 2 2的正整数 b b b

满足题意的 a a a最多有 b − 1 b-1 b1项,每一项都是 b + 1 b+1 b+1的倍数,最大项为 ( b − 1 ) ∗ ( b + 1 ) (b-1)*(b+1) (b1)(b+1)


所以对于每个 b b b,我们可以先求出 1 1 1 x x x内有多少 b + 1 b+1 b+1的倍数(即 ⌊ x b + 1 ⌋ \lfloor\frac x {b+1}\rfloor b+1x个)

在计算答案时,根据规律需要将其与 b − 1 b-1 b1取小

但是这种方法的时间复杂度为 O ( y = 1 0 9 ) O(y=10^9) O(y=109),不可行


考虑优化,发现如果 ( b − 1 ) ∗ ( b + 1 ) > x (b-1)*(b+1)\gt x (b1)(b+1)>x,即 ⌊ x b + 1 ⌋ < b − 1 \lfloor\frac x {b+1}\rfloor \lt b-1 b+1x<b1

x x x的限制,会有一段段连续的 b b b对应的答案数量相同,且答案均为 ⌊ x b + 1 ⌋ \lfloor\frac x {b+1}\rfloor b+1x

直接考虑分块,令 t = ⌊ x b + 1 ⌋ t=\lfloor\frac x {b+1}\rfloor t=b+1x表示当前段的答案,再通过 ⌊ x t ⌋ \lfloor\frac x t\rfloor tx来求出满足答案为 t t t的最大的 b + 1 b+1 b+1的值

故此时最大的 b b b应为 ⌊ x t ⌋ − 1 \lfloor\frac x t\rfloor-1 tx1,注意与 y y y取小即可

该段的答案即段长度*t,其后让 b b b直接成为右端点 + 1 +1 +1即可


( b − 1 ) ∗ ( b + 1 ) ≤ x (b-1)*(b+1)\le x (b1)(b+1)x时,对于每个 b b b的答案数量均为 b − 1 b-1 b1

故我们可以求出满足 ( b − 1 ) ∗ ( b + 1 ) ≤ x (b-1)*(b+1)\le x (b1)(b+1)x以及 b ≤ y b\le y by的最大的 b b b

那么答案就是 1 + 2 + 3 + ⋯ + ( b − 1 ) 1+2+3+\cdots +(b-1) 1+2+3++(b1),直接等差求和公式即可


对于这个最大的满足 ( b − 1 ) ∗ ( b + 1 ) ≤ x (b-1)*(b+1)\le x (b1)(b+1)x b b b,先忽略条件 b ≤ y b\le y by,结论是 m a x b = ⌊ x ⌋ maxb=\lfloor\sqrt x\rfloor maxb=x m a x b = ⌊ x ⌋ + 1 maxb=\lfloor\sqrt x\rfloor +1 maxb=x +1

或者这里也可以打表找规律

Codeforces 1485C - Floor and Mod (分块、数学)_第2张图片

对于 m a x b + 1 maxb+1 maxb+1 y y y,还是分块处理


代码

#include
using namespace std;
typedef long long ll;

void solve()
{
     
    int x,y;
    scanf("%d%d",&x,&y);
    
    int b=sqrt(x)+1;
    if(1LL*(b-1)*(b+1)>x)
        b--;
    b=min(b,y); //注意与y取小
    ll ans=1LL*b*(b-1)/2;
    
    for(b++;b<=y;)
    {
     
        int t=x/(b+1);
        if(t==0)
            break;
        
        int nxt=min(x/t-1,y); // 注意x/t是对于b+1的最大值
        ans+=1LL*(nxt-b+1)*t;
        
        b=nxt+1;
    }
    printf("%lld\n",ans);
}
int main()
{
     
    int T;
    scanf("%d",&T);
    while(T--)
        solve();
    return 0;
}


To cnblogs

你可能感兴趣的:(Codeforces)