CodeForces 319B-Psychos in a Line(单调队列)

B - Psychos in a Line
Time Limit:1000MS     Memory Limit:262144KB     64bit IO Format:%I64d & %I64u
Appoint description: 

Description

有编号为1~N的N个人站成一排(顺序是乱的),每人手中拿着一把枪。每一个时刻,每个人同时瞄准右边的人(如
 
果存在的话),然后如果这个人编号比自己大,则开枪将他打死。因此,一个人可能在开枪的同时被打死。一轮开
 
枪结束后,死亡的人视为离开了队列。那么经过多少时刻才能使得整个序列进入稳定模式—— 即不再有人死亡呢?

Input

第一行是N(<=100000),然后N个数,表示初始的站序。

Output

一行一个正整数,表示需要的时刻(即多少轮同时开枪)。此输出应该为最早满足如下条件的时刻:此时的状态应
 
当等同于此时刻以后任意时刻的状态。

Sample Input

10
10 9 7 8 6 5 3 4 2 1
 

Sample Output

2

Hint

[10 9 7 8 6 5 3 4 2 1]→[10 8 4]→[10]


思路:

  这题其实就是左边大于右边的都被左边的杀死,所以只要从后往前扫,若是左边大于右边,就更新队头为大的值。之后若是找到了一个L>R的值,很明显是要被杀掉的,如果L<R则进队,因为左边的不能将右边的杀掉。之后若存在大于队头的,则进去屠杀一波,直到你比我大,那我就进队等待被杀。


一开始并没有想到这个思路,所以TLE了。

TLE代码:


#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<queue>
using namespace std;

const int T = 100000+50;

int q1[T],q2[T];

int main()
{
#ifdef zsc
	freopen("input.txt","r",stdin);
#endif

	int n,m,i;
	while(~scanf("%d",&n))
	{
		int h1,t1,h2,t2;
		h1=t1=h2=t2=0;
		for(i=0;i<n;++i){
			scanf("%d",&m);
			q1[t1++]=m;
		}
		bool flag = false;
		int cnt = 0,tar=n;
		while(!flag)
		{
			flag = true;
			int cur = q1[h1++];
			q2[t2++]=cur;
			while(h1<t1)
			{
				int tmp = q1[h1++];
				if(cur<tmp){
					q2[t2++]=tmp;
					flag = false;
				}
				cur = tmp;
			}
			if(t2-h2==tar)break;
			cnt++;
			h1 = t1 = 0;
			while(h2<t2)
			{
				q1[t1++] = q2[h2++];
			}
			tar = t1-h1;
			h2 = t2 = 0;
		}
		printf("%d\n",cnt);
	}

	return 0;
}



AC代码:


#include<iostream>
#include<functional>
#include<algorithm>
#include<cstring>
#include<string>
#include<vector>
#include<cstdio>
#include<cmath>
#include<map>
using namespace std;
#define CRL(a) memset(a,0,sizeof(a))
#define QWQ ios::sync_with_stdio(0)
typedef unsigned __int64 LL;
typedef  __int64 ll;
const int T = 100000+50;
const int mod = 1000000007;

int cnt,v[T],cur[T],D[T];

int main()
{
#ifdef zsc
    freopen("input.txt","r",stdin);
#endif

	int i,j,k,n,m;

	while(~scanf("%d",&n))
	{
		memset(D,0,sizeof(D));
		for(i=1;i<=n;++i){
			scanf("%d",&v[i]);
		}
		cnt = 0;
		int ans=0;
		for(i=n;i>0;--i){//从下标大的到小的
			while(cnt&&v[cur[cnt-1]]<v[i])//若左边的数比右边大,将队列的数出队
			{
				D[i] = max(D[i]+1,D[cur[--cnt]]);//统计出队的次数
			}
			cur[cnt++] = i;
			ans = max(ans,D[i]);
		}
		printf("%d\n",ans);
	}

    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值