当前位置: 首页 > ds >正文

洛谷P4479第K大斜率

P4479第K大斜率
我采用了二分答案和树状数组统计顺序对的方法解决第k大斜率问题。以下是对代码思路的总结和关键点分析:

代码思路总结:

  1. 输入与预处理

    • 读入 n 个点的坐标,存储到数组 arr 中。
    • 对点按 x 坐标升序排序,若 x 相同则按 y 降序排序(避免斜率不存在的点对影响统计)。
  2. 二分答案框架

    • 二分斜率 mid,初始范围 [-1e9, 1e9]
    • 对于每个 mid,通过 check(mid) 函数判断是否存在至少 k 条直线的斜率 ≥ mid
  3. check(mid) 函数

    • 计算转换值:对每个点计算转换值 z_i = y_i - mid * x_i
    • 离散化:将 z_i 排序并离散化为排名(相同值赋予相同排名)。
    • 树状数组统计顺序对
      • 按原顺序(排序后的点顺序)遍历每个点。
      • 查询树状数组中排名 ≤ 当前点排名的点的个数(即满足 z_j ≥ z_ij < i 的点对数)。
      • 累加顺序对数量,若累计值 ≥ k 则返回 true
      • 更新树状数组(当前点排名位置 +1)。
    • 若遍历结束累计值 < k,返回 false
  4. 二分调整

    • check(mid)true,说明 mid 偏小(有足够多斜率 ≥ mid 的直线),调整左边界 l = mid
    • 若为 false,说明 mid 偏大,调整右边界 r = mid
    • 最终 l 即为第 k 大斜率的向下取整结果。
  5. 输出:二分结束后输出 l

关键点分析:

  • 避免斜率不存在:通过排序策略(x 相同时 y 降序)确保 x 相同的点不会产生有效顺序对(因 z_i 严格递减),从而排除斜率不存在的点对。
  • 离散化优化:将 z_i 离散化为排名,将值域压缩到 [1, n],适合树状数组处理。
  • 顺序对统计:树状数组动态维护已遍历点的排名分布,高效查询当前点的顺序对数量。
  • 二分正确性:二分目标为最大的 mid 满足至少 k 条直线斜率 ≥ mid,该 mid 即第 k 大斜率的向下取整值。
  • 复杂度:二分过程 O(log(2e9)),每次 check 离散化 O(n log n),树状数组操作 O(n log n),总复杂度 O(n log n log(2e9)),可接受。

代码优化建议:

  1. 提前退出优化:在 check 函数中,一旦累计顺序对数量 ≥ k 即可提前返回 true,减少无效计算。
  2. 树状数组清零:每次 check 前通过初始化保证树状数组归零,避免脏数据。
  3. 离散化处理:对相同 z_i 赋予相同排名,确保顺序对统计正确性。

代码处理了边界情况(如大值域、斜率不存在、重复 z_i 等),能高效解决大规模数据问题。最终输出向下取整结果符合题目要求。

AC代码

#include<bits/stdc++.h>
#define ll long long
#define samplepassediscorrect for(;;)
#define ull unsigned long long
#define jiasu ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define lowbit(x) (x&(-x))
#define N 100050
using namespace std;
struct point{ll x,y;
}arr[N]; 
bool cmp(point &s1,point &s2){if(s1.x==s2.x) return s1.y>s2.y;return s1.x<s2.x;
}
ll n,b[N],k;
struct Fenwick_Tree{ll tree[N]={0};void update(ll x,ll d){while(x<=n){tree[x]+=d;x+=lowbit(x);}}ll sum(ll x){ll ans=0;while(x>0){ans+=tree[x];x-=lowbit(x);}return ans;}
}; 
struct temp{ll x,num;
}a[N];
bool cmp2(temp &s1,temp &s2){return s1.x<s2.x;}
bool check(ll mid){for(int i=1;i<=n;i++){a[i].num=i;a[i].x=arr[i].y-mid*arr[i].x;}sort(a+1,a+1+n,cmp2);b[a[1].num]=1;ll now=a[1].x,cnt=1;for(int i=2;i<=n;i++){if(a[i].x!=now){b[a[i].num]=++cnt;now=a[i].x;}else b[a[i].num]=cnt;}Fenwick_Tree r;ll sum=0;for(int i=1;i<=n;i++){		sum+=r.sum(b[i]);r.update(b[i],1);if(sum>=k) return true;}	return false;
}
int main(){
jiasu;
cin>>n>>k;
for(int i=1;i<=n;i++)cin>>arr[i].x>>arr[i].y;
sort(arr+1,arr+1+n,cmp);
ll l=-1e9,r=1e9;
while(l+1<r){ll mid=(l+r)/2;if(check(mid)) l=mid;else r=mid;
}
cout<<l;return 0;
} 
http://www.xdnf.cn/news/16935.html

相关文章:

  • c#保留小数点后几位 和 保留有效数字
  • 【智能体agent】入门之--4.1 autogen agentic rag
  • C++继承中虚函数调用时机问题及解决方案
  • CG--逻辑判断1
  • 译 | BBC Studios团队:贝叶斯合成控制方法SCM的应用案例
  • C++ --- stack和queue的使用以及简单实现
  • 第三章 网络安全基础(一)
  • PendingIntent相关流程解析
  • 京东零售在智能供应链领域的前沿探索与技术实践
  • 逻辑回归召回率优化方案
  • 《协作画布的深层架构:React与TypeScript构建多人实时绘图应用的核心逻辑》
  • 插件升级:Chat/Builder 合并,支持自定义 Agent、MCP、Rules
  • Spring Boot 2.1.18 集成 Elasticsearch 6.6.2 实战指南
  • 使用GPU和NPU视频生成的优劣对比
  • 修改DeepSeek翻译得不对的V语言字符串文本排序程序
  • (线段树)SP2916 GSS5 / nfls #2899 查询最大子段和 题解
  • 烽火HG680-KX-海思MV320芯片-2+8G-安卓9.0-强刷卡刷固件包
  • 一种新的分布式ID生成方案--ULID
  • 自学嵌入式 day40 51单片机
  • Web开发-PHP应用弱类型脆弱Hash加密Bool类型Array数组函数转换比较
  • sqli-labs:Less-17关卡详细解析
  • IIS 让asp.net core 项目一直运行
  • 8.1 开始新的学习历程
  • linux编译基础知识-工具链
  • 数据结构与算法——字典(前缀)树的实现
  • 抢占先机,PostgreSQL 中级专家认证的职业跃迁
  • React 19 革命性升级:编译器自动优化,告别手动性能调优时代
  • Linux编程: 10、线程池与初识网络编程
  • Docker Compose入门(2)
  • Linux系统编程Day3-- Linux常用操作(续)