• 序列查询新解


    题目背景

    上一题“序列查询”中说道:
    A=[A0,A1,A2,⋯,An] 是一个由 n+1 个 [0,N) 范围内整数组成的序列,满足 0=A0小于等于 x 的整数里最大的数的下标

    对于给定的序列 A 和整数 x,查询 f(x) 是一个很经典的问题,可以使用二分搜索在 O(log⁡n) 的时间复杂度内轻松解决。但在 IT 部门讨论如何实现这一功能时,小 P 同学提出了些新的想法。

    题目描述

    小 P 同学认为,如果事先知道了序列 A 中整数的分布情况,就能直接估计出其中小于等于 x 的最大整数的大致位置。接着从这一估计位置开始线性查找,锁定 f(x)。如果估计得足够准确,线性查找的时间开销可能比二分查找算法更小。

    比如说,如果 A1,A2,⋯,An 均匀分布在 (0,N) 的区间,那么就可以估算出:
    f(x)≈(n+1)⋅xN

    为了方便计算,小 P 首先定义了比例系数 r=⌊Nn+1⌋,其中 ⌊ ⌋ 表示下取整,即 r 等于 N 除以 n+1 的商。进一步地,小 P 用 g(x)=⌊xr⌋ 表示自己估算出的 f(x) 的大小,这里同样使用了下取整来保证 g(x) 是一个整数。

    显然,对于任意的询问 x∈[0,N),g(x) 和 f(x) 越接近则说明小 P 的估计越准确,后续进行线性查找的时间开销也越小。因此,小 P 用两者差的绝对值 |g(x)−f(x)| 来表示处理询问 x 时的误差。

    为了整体评估小 P 同学提出的方法在序列 A 上的表现,试计算:
    error(A)=∑i=0N−1|g(i)−f(i)|=|g(0)−f(0)|+⋯+|g(N−1)−f(N−1)|

    输入格式

    从标准输入读入数据。

    输入的第一行包含空格分隔的两个正整数 n 和 N。

    输入的第二行包含 n 个用空格分隔的整数 A1,A2,⋯,An。

    注意 A0 固定为 0,因此输入数据中不包括 A0。

    输出格式

    输出到标准输出。

    仅输出一个整数,表示 error(A) 的值。

    样例1输入

    1. 3 10
    2. 2 5 8

    Data

    样例1输出

    5

     

    思路:对于枚举的区间[a[i - 1], a[i] - 1),计算出其gx的取值范围,然后按gx去分段,因为当前区间的所有x,其fx = i - 1。

    1. #include
    2. using namespace std;
    3. #define x first
    4. #define y second
    5. #define endl '\n'
    6. #define rep(i,a,n) for (int i = a; i < n; i ++ )
    7. #define repn(i,a,n) for (int i = a; i <= n; i ++ )
    8. #define pb push_back
    9. #define IOS ios::sync_with_stdio(false); cin.tie(0);cout.tie(0);
    10. typedef long long ll;
    11. typedef pair<int,int> PII;
    12. ll gcd(ll a,ll b) { return b ? gcd(b,a % b) : a; }
    13. const int mod = 1e9+7;
    14. int n, k;
    15. const int N = 100010;
    16. int a[N];
    17. ll ans;
    18. int main()
    19. {
    20. IOS;
    21. cin >> n >> k;
    22. repn(i, 1, n)
    23. cin >> a[i];
    24. a[n + 1] = k;
    25. int t = k / (n + 1);
    26. for (int i = 1; i <= n + 1; i ++ )
    27. {
    28. ll l = a[i - 1], r = a[i] - 1;//枚举区间[l, r);
    29. ll gl = l / t, gr = r / t;
    30. ll x = i - 1;
    31. //将每一段分成三部分:
    32. //最开始的部分,中间部分,最后的部分
    33. //最开始和最后部分可能不完整
    34. //也可能开始部分和最后部分是一个数
    35. if(gl == gr)//如果开始和最后部分相同
    36. {
    37. ans += (r - l + 1) * labs(gr - x);
    38. }
    39. else//加上开始部分和最后部分
    40. {
    41. ans += (t - (l % t)) * labs(gl - x);
    42. ans += (r % t + 1) * labs(gr - x);
    43. }
    44. //加上中间完整的部分
    45. for (int j = gl + 1; j < gr; j ++ ) ans += t * labs(j - x);
    46. }
    47. cout << ans << endl;
    48. return 0;
    49. }

  • 相关阅读:
    渗透面试经验分享
    Flink JobManager的高可用配置
    赶紧进来看看---详细介绍五种常用字符串库函数 以及对库函数的模拟实现
    Laravel 不经常用的小技巧
    2022年5月编程语言排行看看学什么吃香?
    4种实用的制作URL 文件的方法
    数据库(mysql)之用户管理
    [Python进阶] Pyinstaller打包模式
    思科拟推出PuzzleFS驱动,采用Rust语言开发
    融入BPM的低代码平台,让企业业务活起来
  • 原文地址:https://blog.csdn.net/m0_61837058/article/details/126675081