abc260_e At Least One 题解
At Least One
题意
给定一个整数
- 整数序列为
的一个子段且序列长度为 。 - 对于
,满足 或者 在整数序列中出现过(可以都出现,不可以都不出现)。
求
数据范围
。 。 。
思路
暴力
枚举左右端点,判断是否满足要求,统计答案。
时间复杂度:
优化
枚举左右端点就
- 对于所有
,区间 必然满足要求。
也就是说,对于每个左端点为
枚举左端点,对于每个左端点
对了,这个只能提供常数优化,重要的还是思想。
最终正解
枚举左端点
又是一顿观察,我们可以发现:随着
- 很显然,对于一个
,如果 ,那么对于它来说,右指针并不需要移动,只需保持 就行了。 - 反之,如果
,那么 至少也要移动到 去,即 。 - 而如果
,那么就可以退出 循环了,后面的必然都不合法。
做法就出来了,先预处理出当左端点为
- 对于每个
, 。
然后就是枚举左端点
复杂度
- 时间:
。 - 空间:
。
Code
挑战最短代码,不服来战。
点击查看代码
#include <iostream> #include <algorithm> using namespace std; const int N = 2e5 + 10; int n, m, a, b, c[N], mr, ans[N]; int main () { ios::sync_with_stdio(0), cin.tie(0); cin >> n >> m; mr = m; for (int i = 1; i <= n; i++) { cin >> a >> b; c[0] = max(c[0], a), c[a + 1] = max(c[a + 1], b), mr = min(mr, b); // i = 1 时右端点至少为 max(a[i]),更新 c 数组 } for (int i = 1; i <= mr; i++) { c[i] = max({c[i - 1], c[i], i}); // 前缀最大值 ans[c[i] - i + 1]++, ans[m - i + 2]--; // 差分 } for (int i = 1; i <= m; i++) { ans[i] += ans[i - 1]; // 还原差分数组 cout << ans[i] << ' '; } return 0; }
本文作者:wnsyou の blog
本文链接:https://www.cnblogs.com/wnsyou-blog/p/17428344.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步