Codeforces 1485C

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


题意

给定(x,y),询问当(1le ale x, 1le ble y)时,(lfloor frac a b floor=a mod b)的对数

限制

(1le x,yle 10^9)




思路

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

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

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

根据(a mod b=a-lfloor frac a b floor*b),最多只能够化到(a=(b+1)*lfloor frac a b floor)

可得(frac a {b+1}=lfloor frac a b floor)

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

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


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

pic1

得到规律:

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

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


所以对于每个(b),我们可以先求出(1)(x)内有多少(b+1)的倍数(即(lfloorfrac x {b+1} floor)个)

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

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


考虑优化,发现如果((b-1)*(b+1)gt x),即(lfloorfrac x {b+1} floor lt b-1)

(x)的限制,会有一段段连续的(b)对应的答案数量相同,且答案均为(lfloorfrac x {b+1} floor)

直接考虑分块,令(t=lfloorfrac x {b+1} floor)表示当前段的答案,再通过(lfloorfrac x t floor)来求出满足答案为(t)的最大的(b+1)的值

故此时最大的(b)应为(lfloorfrac x t floor-1),注意与(y)取小即可

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


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

故我们可以求出满足((b-1)*(b+1)le x)以及(ble y)的最大的(b)

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


对于这个最大的满足((b-1)*(b+1)le x)(b),先忽略条件(ble y),结论是(maxb=lfloorsqrt x floor)(maxb=lfloorsqrt x floor +1)

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

pic2

对于(maxb+1)(y),还是分块处理


代码

#include<bits/stdc++.h>
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
",ans);
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
        solve();
    return 0;
}


原文地址:https://www.cnblogs.com/stelayuri/p/14399671.html