who is in front of me 解题报告

题目描述:N(1<=N<=50005)个学生站成一个纵队,每个人只能看到前面身高比他高(严格大于)的人

              求所有人中能看到的最大人数

分析:对于某个人A,设前面第一个身高比他高的人是B。如果B不存在,那么A看到0个人。若B存在,那么A既能看到B,也能看到B所能看到的人(PS:题意是每个人只能看到身高严格大于自己的人,身高与自己相同的人视为看不见)。

        状态表示:F(x)表示x能看到的人数

        转移方程:F(A)=F(B)+1

        怎么才能很快找到A前面第一个比他高的人是谁?对于每个人x,记录他前面第一个比他高的人legt[x]。对于每个人A,我们比较A和A-1的高矮,如果A-1比A高,那么A-1自然是第一个比他高的人。否则我们寻找第一个比A-1高的人,也就是left[A-1],因为在A-1与left[A-1]之间的所有人,身高都比A-1矮,他们也自然不可能比A高。比较A与left[A-1]的高矮,如果不行再找left[left[A-1]]...,直到找到比A高的人,或者发现没有一个人比A高。然后可以用dp求解了。

        计算left的代码如下,h为每个人的高度:

        for(int i=0;i<N;i++){

        int j;

        for(j=i-1;j>=0&&h[j]<=h[i];j=left[j])   ;

        left[i]=j;

        }

 1 #include<cstdio>
 2 int T,n,h[50005],num[50005],left[50005];
 3 int main()
 4 {
 5     scanf("%d",&T);
 6     while(T--)
 7     {
 8         scanf("%d",&n);
 9         for(int i=0; i<n; i++)
10             scanf("%d",&h[i]);
11         int best=0;
12         for(int i=0; i<n; i++)
13         {
14             int j;
15             for(j=i-1; j>=0&&h[j]<=h[i]; j=left[j])
16                 ;
17             left[i]=j;
18             if(j==-1) num[i]=0;
19             else num[i]=num[j]+1;
20             best= best>num[i] ? best : num[i];
21         }
22         printf("%d
",best);
23     }
24     return 0;
25 }
原文地址:https://www.cnblogs.com/sage-blog/p/3646918.html