Codeforces Round #701 (Div. 2) C. Floor and Mod (数学/思维/整除分块)

折跃坐标: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(1ax,1by)

数学思路:

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 kb+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 1axandk<b
可以得到 k = m i n ( b − 1 , x b + 1 ) k = min(b-1,\frac{x}{b+1}) k=min(b1,b+1x)
接下来,我们希望知道一个关于k的分段函数
b − 1 < x b + 1 b-1 <\frac{x}{b+1} b1<b+1x
( b + 1 ) ∗ ( b − 1 ) < x (b+1)*(b-1)<x (b+1)(b1)<x
b 2 − 1 < x b^2 -1 < x b21<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=b1(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 (ji+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;
}
  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Abmcar

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值