Codeforces Round #446 (Div. 2)B. Wrath

B. Wrath
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

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.

Input

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.

Output

Print one integer — the total number of alive people after the bell rings.

Examples
input
4
0 1 0 10
output
1
input
2
0 0
output
2
input
10
1 1 3 0 0 0 2 1 0 3
output
3
Note

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);
	}
}



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值