首页 > 其他分享 >CF895B XK Segments 题解 二分

CF895B XK Segments 题解 二分

时间:2024-08-13 21:55:48浏览次数:13  
标签:满足条件 le 下标 int 题解 Segments long CF895B 范围

题目链接:https://codeforces.com/problemset/problem/895/B

题目大意

给你一个长度为 \(n\) 的数列 \(a_1, a_2, \ldots, a_n\)。求数列中存在多少个不同的下标对 \((i, j)\) 满足如下条件:

\(a_i \le a_j\) 并且恰好有 \(k\) 个整数 \(y\) 满足 \(a_i \le y \le a_j\) 且 \(y\) 能被 \(x\) 整除。

注:在本题中,若 \(i \neq j\),则下标对 \((i, j)\) 和下标对 \((j, i)\) 是不同的下标对。

解题思路

首先我们可以将 \(a_1 \sim a_n\) 从小到大排序。

很明显排序前后的下标对数量不会变化。

但是排序后和下标 \(i\) 构成满足条件的下标对 \((i, j)\) 的下标 \(j\) 将会在一个连续的范围内。

其次要注意,本题中数据处理的过程中可能会发生超出 int 范围的情况,所以干脆全部都开 long long。即:

#define int long long

然后我们就可以枚举每个下标 \(i\),判断 \(a_i\) 开始(即下标 \(i, i+1, i+2, \ldots, n\) 范围内)存在多少个下标 \(j\) 满足

\(a_i \le a_j\) 并且恰好有 \(k\) 个整数 \(y\) 满足 \(a_i \le y \le a_j\) 且 \(y\) 能被 \(x\) 整除。

这个条件,然后把数量加起来就可以了。

具体来说:

  • 当 \(i = 1\) 时,判断 \([1, n]\) 范围内存在多少下标 \(j\) 和 \(i\) 构成的下标对 \((i, j)\) 满足上述条件;
  • 当 \(i = 2\) 时,判断 \([1, n]\) 范围内存在多少下标 \(j\) 和 \(i\) 构成的下标对 \((i, j)\) 满足上述条件;
  • ……
  • 当 \(i = n\) 时,判断 \([1, n]\) 范围内存在多少下标 \(j\) 和 \(i\) 构成的下标对 \((i, j)\) 满足上述条件。

即对于每个下标 \(i\) 判断区间 \([1, n]\) 范围内存在多少个下标 \(j\) 满足条件。

在 \(a_i = a_j\) 时,\(j\) 甚至可能小于 \(i\)。

(注意 \(i\) 可以等于 \(j\),即下标对 \((i, i)\) 也可能是满足条件的)

而且我们会发现,对于每个下标 \(i\),满足条件的下标 \(j\) 是一个连续的区间,这很好理解:

设满足条件的 \(j\) 所在的区间为 \([l_i, r_i]\)(而一整个区间是 \([1, n]\)),则:

  • 区间 \([1, l_i - 1]\) 范围内:\(x\) 的倍数 \(\lt k\) 个;
  • 区间 \([l_i, r_i]\) 范围内:\(x\) 的倍数恰好 \(k\) 个;
  • 区间 \([r_i + 1, n]\) 范围内:\(x\) 的倍数 \(\gt k\) 个。

所以我们现在要做的事情就是找 \(i\) 对应的最小值 \(l_i\) 和最大值 \(r_i\)。

有一种特殊情况,\(k = 0\)。

\(k = 0\) 时

此时若 \(a_i\) 是 \(x\) 的倍数,则无解。(因为此时至少有一个 \(a_i\) 是 \(x\) 的倍数)

若 \(a_i\) 不是 \(x\) 的倍数,则 \(l_i = a_i\),\(r_i = \lceil \frac{a_i}{x} \rceil \times x - 1\)。

\(k \gt 0\) 时

\(l_i = \lceil \frac{a_i}{x} \rceil \times x + (k - 1) \times x\)

\(r_i = l_i + x - 1\)

确定好 \(l_i\) 和 \(r_i\) 之后 —— 我们用 l 表示 \(l_i\),用 r 表示 \(r_i\),那么

lower_bound(a+i, a+n+1, l) - a

对应的就是下标 \(l_i\)。

upper_bound(a+i, a+n+1, r) - a - 1

对应的就是下标 \(r_i\)。

则 \([l_i, r_i]\) 范围内满足条件的下标一共有 \(r_i - l_i + 1\) 即:

upper_bound(a+i, a+n+1, r) - lower_bound(a+i, a+n+1, l)

个。

对于每个下标 \(i\),确定好 \(l_i\) 和 \(r_i\) 之后,对上式进行累加即可。

示例程序

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 5;
#define int long long
int n, x, k, a[maxn], ans;

signed main() {
    cin >> n >> x >> k;
    for (int i = 1; i <= n; i++)
        cin >> a[i];
    sort(a+1, a+n+1);
    for (int i = 1; i <= n; i++) {
        int l, r;
        if (k == 0) {
            if (a[i] % x == 0)
                continue;
            l = a[i], r = (a[i] + x - 1) / x * x - 1;
        }
        else {
            l = (a[i] + x - 1) / x * x + (k - 1) * x;
            r = l + x - 1;
        }
        ans += upper_bound(a+1, a+n+1, r) - lower_bound(a+1, a+n+1, l);
    }
    cout << ans << endl;
    return 0;
}

标签:满足条件,le,下标,int,题解,Segments,long,CF895B,范围
From: https://www.cnblogs.com/quanjun/p/18357779

相关文章

  • 题解:CF1957A Stickogon
    原地址:这里思路首先看样例41121162233339422224244首先可以肯定当\(t\)为\(1\)和\(2\)时不能组成多边形,易知要组成最多的多边形,三角形更有性价比,观察样例\(t\)为\(6\)可以发现,只要用相同的木棍除以\(3\)取整便是答案,可能会有人问了,那我用......
  • 题解:AT_abc352_c [ABC352C] Standing On The Shoulders
    原地址:这里大意几个吃饱了撑的巨人在玩叠罗汉,每个人踩在前一个人的肩膀上,求这个叠罗汉最高有多高。思路直接先求出所有巨人的肩高之和,然后再一个一个枚举看加上哪一个巨人的头高最大就行了。代码#include<iostream>usingnamespacestd;inta[200005],b[200005];intmain......
  • 题解:CF1971B Different String
    原地址:这里题意给出字符串\(s\),询问更改\(s\)的排列顺序后与原来的\(s\)是否不同,不同输出YES,否则输出NO。思路只要判断字符串中含有不同的字符即可。代码#include<iostream>#include<cstdio>usingnamespacestd;intmain(){ intt; scanf("%d",&t); while(t-......
  • 【题解】 [NOIP 2002 普及组] 产生数
    题目描述题目大意给定\(k\)个规则,规则为“使一位数可变换成另一个一位数”。求整数\(n\)根据规则经过若干次(可以为0次或多次)变化,能生成的整数个数。思路该题主要考察:Floyd传递闭包,高精度乘法。显而易见,规则具有传递性。举个例子,1可变换成2,2可变换成3,则1可变换成3。当然......
  • P8997 题解
    P8997思路按题意模拟,用栈建出二叉树,叶子节点是要填的值,非叶子是运算符。判断一个叶子能贡献能填哪些数并最终成为答案,即dp计算要使该叶子的值\(ans\)成为答案最少要填\(num0\)个\(<=ans\)和\(num1\)个\(>ans\)的数。发现dp只与\(\leans\)和\(>ans\)的数的个......
  • P8996 题解
    P8996思路当有\(a_i<a_j\)时,先放\(a_i\),再放\(i\)之后连续的\(a_k<a_i\)。设\(i\)后第一个比\(a_i\)大的位置是\(nxt_i\),对于一个前缀最大值位置\(i\),合并后\([i,nxt_i)\)的顺序不变且依然连续。让前缀最大值\(a_l\)代表整个区间,可以看做合并是将两个序列的前缀......
  • arc182c 题解
    arc182c思路有\(6\)个小于\(14\)的质数,设这\(6\)个质数的指数分别为\(x_1,\dotsb,x_6\)。\(ans=\sum(\prod_{i=1}^d(x_i+1))\)。状压这\(6\)个数,维护\(val_s=\prod_{i=1}^6(x_i\times[s二进制第i位为1]+[s二进制第i位为0])\)。当加入一个数时,某些\(x_i\)会加......
  • CF1294F 题解
    Part.0闲话更好的观看体验目前题解区里大多数巨佬都是采用的树形dp和暴力等方法,看见没有我这种做法,欢迎指出做法问题或hack代码。Part.1题意给定一棵树,选\(3\)个点\(a,b,c\),求\(a\)到\(b\)的路径与\(a\)到\(c\)的路径与\(b\)到\(c\)的路径上一共有多少......
  • 新坑:信息学奥赛一本通题解(3001~3005)
    前言Hello,大家好我是文宇,开个新坑,是关于信息学奥赛一本通的坑,就是信奥赛题解.(这里指编程启蒙的题库)因为作者的洛谷还在写,只是信奥赛的题写的比较多,所以先做信奥赛的.信奥赛的网址是信息学奥赛一本通-编程启蒙(C++版)在线评测系统(挖坑:作者以后可能还会有信奥赛本体......
  • 生活在hzoi上 题解
    生活在hzoi上题解考虑有两棵树怎么做,显然是\(y^{n-k}=y^{n-\left\vertE_1\capE_2\right\vert}\)其中\(E_1\)和\(E_2\)是两棵树的边集发现上边那个\(k\)是两棵树边集交构成的图的连通块个数\(\left\vertE_1\capE_2\right\vert\)就是两棵树交的连通块数量......