一只刷题的北京烤鸭 2024-09-04 07:04 采纳率: 50%
浏览 28

我听不懂,有没有人讲一下

题目
有 n
个线性序列,第 i
个序 列可以表示成 ki×x+bi
的形式(x=0,1,2,…)。
请问将这些序列的数合并起来后,第 m
小的数是多少(重复出现的数合并后也会多次出现)。
输入格式
输入第一行一个数 n
接下来 n
行每行两个数表示 ki,bi
最后一行一个数 m
输出格式
输出一个数表示答案。

样例输入
2
1 2
5 2
8
样例输出
7

数据规模
对于 100%的数据,保证 1≤n≤100000,1≤m≤100000,1≤ki,bi≤1000
这是、代码,但是我没听懂,有没有人再帮我详细的讲一下,谢谢!

#include<bits/stdc++.h>
using namespace std;
int n,m,k[100001],b[100001];
long long calc(int x){
    long long y=0;
    for(int i=1;i<=n;i++){
        if(b[i]<=x)
        y+=(x-b[i])/k[i]+1;
    }
    return y;
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d%d",&k[i],&b[i]);
    }
    scanf("%d",&m);
    int L=0,R=1<<31;
    while(L+1<R){
        int w=(L+R)/2;
        if(calc(w)<m){
            L=w;
        }
        else{
            R=w;
        }
    }
    printf("%d\n",R);
    return 0;
}
  • 写回答

1条回答 默认 最新

  • 2401_86614810 2024-09-08 16:52
    关注

    daimayuan? Y2? 施韩原的写法!二分!如果是,你就去听课吧。

    以下是对这段代码的详细解释:
    一、问题分析
    有 n 个线性序列,每个序列形式为 ki×x + bi(x = 0, 1, 2,...)。要求找出将这些序列的数合并起来后,第 m 小的数。
    二、代码解释
    变量定义
    n:表示线性序列的个数。
    m:要找的合并后序列中的第 m 小的数的位置。
    k[100001] 和 b[100001]:分别存储每个线性序列的系数 k 和常数项 b。
    calc 函数
    这个函数的作用是计算在给定的 x 值下,所有线性序列中小于等于 x 的数的总数。
    long long y = 0:用于累加总数。
    for(int i = 1; i <= n; i++):遍历每个线性序列。
    if(b[i] <= x):如果当前序列的常数项小于等于 x,说明可能存在小于等于 x 的数。
    y += (x - b[i]) / k[i] + 1:计算当前序列中小于等于 x 的数的个数并累加到 y。这里 (x - b[i]) / k[i] 表示满足 ki×x + bi <= x 的最大 x 的值,再加上 1 是因为包括常数项 b[i] 本身也可能小于等于 x。
    main 函数
    scanf("%d", &n):输入线性序列的个数 n。
    循环输入每个序列的 k 和 b:for(int i = 1; i <= n; i++) scanf("%d%d", &k[i], &b[i]);。
    scanf("%d", &m):输入要找的第 m 小的数的位置。
    int L = 0, R = 1 << 31:初始化搜索范围,L 初始为 0,R 初始为一个较大的值(2 的 31 次方)。这里假设所有数都是非负整数,所以 L 从最小的可能值开始,R 从一个足够大的值开始。
    while(L + 1 < R):进行二分搜索。
    int w = (L + R) / 2:取中间值。
    if(calc(w) < m):如果在 w 这个值下,所有线性序列中小于等于 w 的数的总数小于 m,说明第 m 小的数在 w 的右侧,更新 L = w。
    else:如果总数大于等于 m,说明第 m 小的数在 w 或 w 的左侧,更新 R = w。
    printf("%d\n", R):当 L + 1 == R 时,说明找到了第 m 小的数,输出 R。
    三、示例说明
    以样例输入 2,1 2,5 2,8 为例:
    输入 n = 2,表示有两个线性序列。
    输入第一个序列的 k[1] = 1,b[1] = 2,即序列为 x + 2(x = 0, 1, 2,...)。
    输入第二个序列的 k[2] = 5,b[2] = 2,即序列为 5x + 2(x = 0, 1, 2,...)。
    输入 m = 8,要找合并后序列中的第 8 小的数。
    在 main 函数中,初始化 L = 0,R = 1 << 31。然后进入二分搜索循环:
    第一次循环,w = (0 + (1 << 31)) / 2,假设这个值很大。
    调用 calc(w),计算在这个 w 值下小于等于 w 的数的总数。
    如果总数小于 m,说明第 m 小的数在 w 的右侧,更新 L = w。
    如果总数大于等于 m,说明第 m 小的数在 w 或 w 的左侧,更新 R = w。
    不断重复上述过程,缩小搜索范围,直到 L + 1 == R,此时找到了第 m 小的数,输出 R。
    通过这种二分搜索的方法,可以高效地找到合并后序列中的第 m 小的数。

    评论 编辑记录

报告相同问题?

问题事件

  • 创建了问题 9月4日