[CF1796C] Maximum Set 题解

更好的阅读体验?

题意描述

给你一个区间,求一个集合 S , S ∈ [ l , r ] S,S\in[l,r] S,S[l,r] 的最大长度与最长集合的个数。

需要满足 ∀ i , j ∈ S ,    i ∣ j  或  j ∣ i \forall i,j \in S , \ \ i | j \ 或 \ j | i i,jS,  ij  ji,集合长度为 1 1 1 默认合法。

简要分析

不难发现,最长长度的集合长这样 l , l × 2 , l × 2 2 , . . . , l × 2 x l ,l\times 2,l\times 2^2 , ...,l \times2^x l,l×2,l×22,...,l×2x

那么我们就可以处理出集合的最长长度。

接下来考虑仅 × 2 \times 2 ×2 时的集合数量。

显然,我们只需将 r r r 除以 x − 1 x - 1 x1 2 2 2 就可以知道集合的初值所属于的最大区间,即求出了集合数量。

我们考虑到,可以将集合中的某一个 × 2 \times 2 ×2 替换成 × 3 \times3 ×3

如果替换两个即等价于 × 9 \times 9 ×9,这时不妨使用 3 3 3 × 2 \times 2 ×2 即为 × 8 \times 8 ×8 得到更优答案。

对于计算存在一个 × 3 \times 3 ×3 的集合个数,我们如法炮制。

r r r 除以 x − 1 x-1 x1 2 2 2 随后再除以 3 3 3 就可以知道集合的初值所属于的最大区间,即求出了集合数量。

时间复杂度 O ( T log ⁡ r ) O(T\log r) O(Tlogr)

代码实现

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <cmath>
#include <vector>

using namespace std;

typedef long long ll;
const ll maxn = 1e5 + 7;
const ll INF = 1e9 + 7, MOD = 998244353;

inline ll read() {
    char cCc;
    ll xXx = 0, wWw = 1;
    while (cCc < '0' || cCc > '9')
        (cCc == '-') && (wWw = -wWw), cCc = getchar();
    while (cCc >= '0' && cCc <= '9')
        xXx = (xXx << 1) + (xXx << 3) + (cCc ^ '0'), cCc = getchar();
    xXx *= wWw;
    return xXx;
}

inline void write(ll xXx) {
    if (xXx < 0)
        putchar('-'), xXx = -xXx;
    if (xXx > 9)
        write(xXx / 10);
    putchar(xXx % 10 + '0');
}

void solve() {
    ll n = read(), m = read();
    ll tmp = m, ans = 0, cnt = 0, lim;
    if (n * 2 > m) {
        cout << 1 << " " << m - n + 1 << '\n';
        return;
    }
    while (tmp >= n) cnt++, tmp /= 2;
    lim = cnt - 1;
    tmp = m;

    while (lim--) tmp /= 2;

    ans = tmp - n + 1;
    lim = cnt - 2;
    tmp = m;
    while (lim--) tmp /= 2;
    ans += max(0ll, (tmp / 3 - n + 1) * (cnt - 1));
    cout << cnt << ' ' << ans << endl;
}

signed main() {
//    freopen("code.in","r",stdin);
//    freopen("code.out","w",stdout);
    ll T = read();
    while (T--)solve();
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值