Hands that shed innocent blood!
There are n guilty people in a line, the i-th of them holds a claw with length Li. The bell rings and every person kills some of people in front of him. All people kill others at the same time. Namely, the i-th person kills the j-th person if and only if j < i and j ≥ i - Li.
You are given lengths of the claws. You need to find the total number of alive people after the bell rings.
The first line contains one integer n (1 ≤ n ≤ 106) — the number of guilty people.
Second line contains n space-separated integers L1, L2, ..., Ln (0 ≤ Li ≤ 109), where Li is the length of the i-th person's claw.
Print one integer — the total number of alive people after the bell rings.
4 0 1 0 10
1
2 0 0
2
10 1 1 3 0 0 0 2 1 0 3
3
In first sample the last person kills everyone in front of him.
看完这道题我心里就只有一个表情包真的 就是那个一个小人手里拿着一把刀 刀上面写着四十米 然后 说我允许你先跑三十九米 就这张图 23333 超级应景有没有~~~
这道题大概意思是这样的 给你一个序列 然后让你处理下这些元素 然后 给这些数字从1到n的编号 然后用这些编号减去给你的这些序列 这样你就得到了一个新的序列对吧
然后编号为a的人能杀掉编号为b的人 需要两个条件 这两个条件是什么呢 就是a的编号大于b的编号 然后你还要满足的一个条件是这样的就是 比第a个人的编号大的这些人中的dif数组中的值(dif数组表示 当前数字的编号减去Li所得到的值)
看到这道题我第一想法 这不是很简单 每次判断当前这个人能不能活下去的条件就是去查询后面的人中的一个区间最值 然后就很简单的判断了 然后用线段树写了一发 就这样了:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define lson l , mid , rt << 1
#define rson mid + 1 , r , rt << 1 | 1
using namespace std;
const static int N = 1e6 + 100;
const static int inf = 0x7fffffff;
int Min[N << 2], cnt = 0;
int array[N], dif[N];
int n;
void Pushup(int rt)
{
Min[rt] = min(Min[rt << 1] , Min[rt << 1 | 1]);
return ;
}
void Build(int l, int r, int rt)
{
if(l == r) {
Min[rt] = dif[cnt ++];
return ;
}
int mid = (l + r) >> 1;
Build(lson);
Build(rson);
Pushup(rt);
}
int Query(int L , int R, int l , int r , int rt)
{
if(L == n + 1)L -- ;
if(L <= l && r <= R) {
//if(!Min[rt])printf("%d to %d is zeor\n",l , r);
return Min[rt];
}
int mid = (l + r) >> 1;
int res = inf;
if(L <= mid) res = min(res , Query(L , R , lson));
if (R > mid) res = min(res , Query(L , R , rson));
return res;
}
int main()
{
while (~scanf("%d",&n) && n) {
cnt = 1;
for (int i = 0; i < N; i ++ )Min[i] = 0x7fffffff;
for (int i = 1; i <= n; i ++) {
scanf("%d",&array[i]);
dif[i] = i - array[i];
//printf("dif[%d] = %d\n",i + 1, dif[i]);
}
Build(1 , n , 1);
int res = 0;
//printf("6 -> %d\n",Query(6 , n , 1 , n , 1));
for (int i = 1; i < cnt ; i ++) {
if (Query(i + 1 , n, 1, n, 1) <= i)res ++;
//printf("from %d to n's minner num is %d\n",i , Query(i + 1, n, 1, n, 1));
}
printf("%d\n",n - res + 1);
}
}
但是后来才知道 这道题你可以用维护最小值的方法 用递推来解决 才知道 思维定势太可怕了 然后改了改第一种的版本
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define lson l , mid , rt << 1
#define rson mid + 1 , r , rt << 1 | 1
using namespace std;
const static int N = 1e6 + 100;
const static int inf = 0x7fffffff;
int Min[N << 2], cnt = 0;
int array[N], dif[N];
int n;
void Pushup(int rt)
{
Min[rt] = min(Min[rt << 1] , Min[rt << 1 | 1]);
return ;
}
void Build(int l, int r, int rt)
{
if(l == r) {
Min[rt] = dif[cnt ++];
return ;
}
int mid = (l + r) >> 1;
Build(lson);
Build(rson);
Pushup(rt);
}
int Query(int L , int R, int l , int r , int rt)
{
if(L == n + 1)L -- ;
if(L <= l && r <= R) {
//if(!Min[rt])printf("%d to %d is zeor\n",l , r);
return Min[rt];
}
int mid = (l + r) >> 1;
int res = inf;
if(L <= mid) res = min(res , Query(L , R , lson));
if (R > mid) res = min(res , Query(L , R , rson));
return res;
}
int main()
{
while (~scanf("%d",&n) && n) {
cnt = 1;
for (int i = 0; i < N; i ++ )Min[i] = 0x7fffffff;
for (int i = 1; i <= n; i ++) {
scanf("%d",&array[i]);
dif[i] = i - array[i];
//printf("dif[%d] = %d\n",i + 1, dif[i]);
}
// Build(1 , n , 1);
int res = 0;
//printf("6 -> %d\n",Query(6 , n , 1 , n , 1));
int minn = dif[n];
/*for (int i = ; i < cnt ; i ++) {
if (Query(i + 1 , n, 1, n, 1) <= i)res ++;
//printf("from %d to n's minner num is %d\n",i , Query(i + 1, n, 1, n, 1));
}*/
for (int i = n- 1; i > 0 ; i --) {
if(minn > i) res ++;
minn = min(minn , dif[i]);
}
printf("%d\n",res + 1);
}
}