您的位置:首页 > 其它

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

2016-03-30 14:28 281 查看
B - Psychos in a Line
Time Limit:1000MS     Memory Limit:262144KB     64bit IO Format:%I64d
& %I64u
Submit Status Practice CodeForces
319B

Appoint description: 
pearfish16  (2015-03-08)System Crawler  (2016-03-27)

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  codeforces