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

最美丽的区间

#include <bits/stdc++.h> //  双指针滑动窗口(双指针)
using namespace std;
typedef long long ll;int main()
{ll n, S, length;cin >> n >> S;vector<ll> a(n+1);for(ll i=1;i<=n;i++){cin >> a[i];}ll sum =0;ll minlength = n+1;ll left =1;for(ll right=1;right<=n;right++){sum +=a[right]; //扩展窗口// 当窗口内的和 >= S,收缩窗口while(sum>=S){minlength = min(minlength,right-left+1);sum -=a[left]; // 缩小窗口left ++;}}if(minlength == n+1)// 没有找到符合条件的区间{cout << 0 <<endl;}else {cout << minlength<<endl;}return 0;
}

前缀和+二分

#include <bits/stdc++.h> //  前缀和+二分法
using namespace std;
typedef long long ll;ll n, S;bool valid(ll mid,vector<ll>& b)
{for(ll j=1;j + mid - 1 <=n;j++){ll l = j;ll r = j + mid - 1;if(b[r]-b[l-1] >= S )return true;}return false;
}int main()
{ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr);cin >> n >> S;vector<ll> a(n+1);vector<ll> b(n+1);ll max_num =-1;  for(ll i=1;i<=n;i++){cin >> a[i];b[i]=b[i-1] + a[i];max_num= max(max_num,a[i]);}if(b[n] < S )cout << 0 << endl;else if (max_num >= S)cout << 1 << endl;else{ll l=1;ll r =n;while(l<r){ll mid = (l+r) >>1;if(valid(mid,b))r=mid;elsel=mid+1;}cout << r << endl;// cout << l << endl;}return 0;
}

while (l < r) {ll mid = (l + r) >> 1;if (valid(mid)) r = mid;     // ✅ mid 可行,往更短尝试else l = mid + 1; // ❌ mid 不行,必须加长
}

第一个满足条件的最小值,也叫 lower_bound 类似逻辑。

  • valid(mid) 是一个单调性函数(子数组长度越大,越可能满足 sum ≥ S

  • 所以:

    • mid 合法,说明答案可能更小 → 把 r = mid(保留 mid)

    • mid 不合法,说明答案只能更大 → 把 l = mid + 1

这个模板二分会不断逼近最小可行值,直到找到第一个合法值(最小长度)

假设答案是 4 

l = 1, r = 7
第一次 mid = 4 → valid(4) = true → r = 4
第二次 mid = 2 → valid(2) = false → l = 3
第三次 mid = 3 → valid(3) = false → l = 4此时 l == r == 4,结束循环

此时的 r(或 l)就是第一个满足条件的最小长度

可以输出

cout << r << endl;  // ✅ 正确,r 是最小满足条件的长度

也可以输出

cout << l << endl;  // ✅ 同样正确,因为最后 l == r

不建议改成 while (l <= r),否则逻辑就需要额外调整,不然会出错

while (l < r) {ll mid = (l + r) >> 1;if (valid(mid))r = mid;elsel = mid + 1;
}

左闭右开/左闭右闭的二分法,用于查找第一个满足条件的值(lower bound)。

  • 每次都保留合法的 mid(即 r = mid

  • 最终 l == r 时退出,l/r 就是我们要找的 最小满足条件的位置

如果你改成 while (l <= r),就会多循环一次:

while (l <= r) {ll mid = (l + r) >> 1;if (valid(mid))r = mid; // 问题点:当 mid == r 时,这样写 r 会一直不动elsel = mid + 1;
}

如果你不做特别处理:

  • 可能陷入死循环(l == r,但 valid(mid) 一直为 true,r 永远不变)

  • 或者你最后拿到的 r 并不是“最小合法值”

注释

#include <bits/stdc++.h> 
using namespace std;
typedef long long ll;     // 简化 long long 为 ll,便于书写ll n, S; // 输入的数组长度 n 和目标子段和 S// 检查是否存在长度为 mid 的子数组,其和 >= S
bool valid(ll mid, vector<ll>& b)
{for (ll j = 1; j + mid - 1 <= n; j++) // 枚举所有长度为 mid 的连续子数组{ll l = j;ll r = j + mid - 1;// 前缀和优化:b[r] - b[l - 1] 即为 a[l] 到 a[r] 的和if (b[r] - b[l - 1] >= S)return true; // 如果有一个满足条件的,就返回 true}return false; // 所有区间都不满足,则返回 false
}int main()
{ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr); // 提升 cin/cout 效率(关闭同步)cin >> n >> S;// 初始化数组 a 和前缀和数组 b,开 n+1 是因为我们从下标 1 开始vector<ll> a(n + 1);vector<ll> b(n + 1);ll max_num = -1; // 记录数组中的最大值for (ll i = 1; i <= n; i++){cin >> a[i]; // 读入原数组b[i] = b[i - 1] + a[i]; // 构建前缀和数组max_num = max(max_num, a[i]); // 更新最大值}// 边界情况 1:整个数组和都小于 S,不可能满足条件if (b[n] < S)cout << 0 << endl;// 边界情况 2:数组中有单个元素就 ≥ S,那最短子数组长度为 1else if (max_num >= S)cout << 1 << endl;// 否则,二分查找最短满足条件的子数组长度else{ll l = 1;     // 最短可能长度ll r = n;     // 最长可能长度(整个数组)// 二分查找最小满足条件的长度while (l < r){ll mid = (l + r) >> 1;if (valid(mid, b)) // 如果存在一个长度为 mid 的子数组满足条件r = mid;       // 缩小范围,尝试更短的长度elsel = mid + 1;   // 否则尝试更长的长度}cout << r << endl; // 最终的最短长度(即最左满足条件的值)}return 0;
}

滑动窗口法

#include <bits/stdc++.h> 
using namespace std;
typedef long long ll;int main()
{ll n, S, length;cin >> n >> S; // 输入数组长度 n 和目标和 Svector<ll> a(n + 1); // 定义数组,下标从 1 开始for (ll i = 1; i <= n; i++){cin >> a[i]; // 读入数组元素}ll sum = 0;               // 当前窗口内的元素和ll minlength = n + 1;     // 初始化最短长度为不可能的最大值ll left = 1;              // 滑动窗口的左边界for (ll right = 1; right <= n; right++){sum += a[right]; // 扩展右边界(窗口右移)// 当窗口内的和满足条件时,尝试收缩左边界while (sum >= S){minlength = min(minlength, right - left + 1); // 更新最短长度sum -= a[left];  // 缩小窗口:移除最左边的元素left++;          // 左指针右移}}// 输出结果:如果没有任何满足条件的区间,则输出 0if (minlength == n + 1){cout << 0 << endl;}else{cout << minlength << endl;}return 0;
}

1372

http://www.xdnf.cn/news/1116.html

相关文章:

  • Pycharm(十五)面向对象程序设计基础
  • AI数字人:品牌营销的新宠与增长密码(6/10)
  • 中间系统-基础
  • 【Redis】字符串类型List 常用命令详解
  • Qt进阶开发:鼠标及键盘事件
  • ​CTGCache ​CTG-Cache TeleDB
  • 前端开发核心知识详解:Vue2、JavaScript 与 CSS
  • Anaconda3使用conda进行包管理
  • 微信小程序 van-dropdown-menu
  • 基于OpenCV的骨骼手势识别分析系统
  • 在任意路径下简单开启jupyter notebook
  • C++ / 引用 | 类
  • sofia-sip 向上注册不成功以及解决办法
  • 用c语言实现——一个带头节点的链队列,支持用户输入交互界面、初始化、入队、出队、查找、判空判满、显示队列、遍历计算长度等功能
  • Oracle--存储过程
  • mybatis mapper.xml中使用枚举
  • Mysql 读写分离(3)之 schema.xml基本配置
  • 简化K8S部署流程:通过Apisix实现蓝绿发布策略详解(上)
  • 物联网 (IoT) 安全简介
  • 《开源大模型选型全攻略:开启智能应用新征程》
  • Ubuntu 上安装 Conda
  • Spark-Streaming核心编程
  • 深度剖析神经网络:从基础原理到面试要点(二)
  • 游戏引擎学习第239天:通过 OpenGL 渲染游戏
  • 三餐四季、灯火阑珊
  • Oracle DBA 高效运维指南:高频实用 SQL 大全
  • 极狐GitLab 项目功能和权限解读
  • 大数据学习(112)-HIVE中的窗口函数
  • Cursor这类编程Agent软件的模型架构与工作流程
  • Flink介绍——实时计算核心论文之Dataflow论文详解