codeforces 892B B. Wrath
https://codeforces.com/problemset/problem/892/B
/*
https://codeforces.com/problemset/problem/892/B
有 n 个有罪的人排成一行,其中第 i 个手持长度为 Li 的爪子。钟声响起,每个人都杀死了他前面的一些人。所有人同时杀死其他人。
也就是说,当且仅当 j < i 且 j ≥ i - Li 时,第 i 个人杀死第 j 个人。
你得到了爪子的长度。您需要找出铃声响起后活着的总人数。
输入
第一行包含一个整数 n(1 ≤ n ≤ 106)--有罪人数。
第二行包含 n 个空格分隔的整数 L1、L2、......、Ln(0 ≤ Li ≤ 109),其中 Li 是第 i 个人爪子的长度。
输出
打印一个整数--铃声响起后活着的总人数。
Examples
InputCopy
4
0 1 0 10
OutputCopy
1
InputCopy
2
0 0
OutputCopy
2
InputCopy
10
1 1 3 0 0 0 2 1 0 3
OutputCopy
3
8
0 0 0 1 0 0 1 2
5
注释
在第一个样本中,最后一个人杀死了他面前的所有人。
*/
//一题多解
//1 差分? O(n)
//2 线段合并,然后二分查找当前元素是否处于一个线段的结束和一个新线段开始的中间 O(nlogn)
//3 官解 第i名能否存活
差分代码
#include <iostream>
#include <cstring>
using namespace std;
const int N = 1000010;
int a[N];
int pre[N];
int n;
int main()
{
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> a[i];
int l = max(0, i - a[i]); int r = i;
pre[l]++; pre[r ]--;
}
int ans = 0;
for (int i = 1; i <= n; i++) {
pre[i] += pre[i - 1];
if (pre[i] == 0) ans++;
}
cout << ans << endl;
return 0;
}
线段合并然后检测点是否在被覆盖的区域里
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1000010;
int a[N];
int n;
struct SEG {
int l;
int r;
} segs[N];
bool cmp(const SEG& a, const SEG& b) {
if (a.l < b.l) return true;
else if (a.l == b.l) return a.r < b.r;
return false;
}
int merges[2 * N];
int idx;
int main() {
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> a[i];
segs[i].l = max(0, i - a[i]);
segs[i].r = i-1;
}
sort(segs + 1, segs + n + 1, cmp);
SEG curr = { -1,-1 };
for (int i = 1; i <= n; i++) {
if (segs[i].l > segs[i].r) continue;
if (curr.r == -1) {
curr = segs[i];
}
if (curr.r >= segs[i].l) {
curr.l = min(curr.l, segs[i].l);
curr.r = max(curr.r, segs[i].r);
}
else {
merges[++idx] = curr.l;
merges[++idx] = curr.r;
curr.l = segs[i].l;
curr.r = segs[i].r;
}
}
if (curr.l <= curr.r) {
merges[++idx] = curr.l;
merges[++idx] = curr.r;
}
merges[++idx] = 1e9 + 10;
int alive = 0;
for (int i = 1; i <= n; i++) {
int l = 0, r = idx;
while (l < r) {
int mid = (l + r) / 2;
if (merges[mid] >= i) r = mid;
else l = mid + 1;
}
if (merges[l] > i && merges[l - 1] < i && l%2) {
alive++;
}
}
cout << alive << endl;
return 0;
}
官方解
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 1000010;
int a[N];
int n;
int backmax[N];
int main() {
cin >> n;
for (int i = 1; i <= n; i++) cin >> a[i];
memset(backmax, 0x3f, sizeof backmax);
int ans = 0;
//逆序求 n到当前i的 爪子能覆盖到的最大位置(也是最小坐标值)
for (int i = n; i >= 1; i--) {
backmax[i] = backmax[i + 1];
if (i < backmax[i]) ans++;
backmax[i] = min(backmax[i], i - a[i]);
//爪子太长 负数了 haha
backmax[i] = max(0, backmax[i]);
}
cout << ans << endl;
return 0;
}
作 者: itdef
欢迎转帖 请保持文本完整并注明出处
技术博客 http://www.cnblogs.com/itdef/
B站算法视频题解
https://space.bilibili.com/18508846
qq 151435887
gitee https://gitee.com/def/
欢迎c c++ 算法爱好者 windows驱动爱好者 服务器程序员沟通交流
如果觉得不错,欢迎点赞,你的鼓励就是我的动力
欢迎转帖 请保持文本完整并注明出处
技术博客 http://www.cnblogs.com/itdef/
B站算法视频题解
https://space.bilibili.com/18508846
qq 151435887
gitee https://gitee.com/def/
欢迎c c++ 算法爱好者 windows驱动爱好者 服务器程序员沟通交流
如果觉得不错,欢迎点赞,你的鼓励就是我的动力


【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
2021-02-18 剑指 Offer 39. 数组中出现次数超过一半的数字
2021-02-18 剑指 Offer 38. 字符串的排列 dfs
2021-02-18 剑指 Offer 37. 序列化二叉树 && 297. 二叉树的序列化与反序列化 bfs
2015-02-18 春节记录