UVALive-4976(二分查找)

一个dp题。复杂度是n*logn(n是for循环从0到n遍历,logn是二分查找)

思路:

预处理:

从前往后扫一遍,更新pre数组(记录每一个元素是子串中连续上升的第几个,如果a[i]>a[i-1],则a[i]=1.否则a[i]=a[i-1]+1,a[i]是题目给的)

从后往前扫一遍,更新aft数组(记录每一个元素是子串中连续下降的第几个,如果a[i]>a[i+1],则a[i]=1.否则a[i]=a[i+1]+1)

二分查找:

初始化dp数组为正无穷(0x3f3f3f3f3f3f3f)

从前向后遍历a[i],更新dp数组,dp数组是一个用来记录长度为i的连续上升子串的最后一个元素的最小值的数组。dp[pre[i]]=min(dp[i],a[i]).这样就可得到当前连续上升子串长度的最后一个元素的最小值。

拼接:对于当前i,有最小的dp[1],dp[2]......dp[i-1],(在代码中,把拼接这一步放在更新dp数组前).然后我们用lower_bound在dp数组中寻找到一个比当前a[i]大一点的dp[j],(如果能找到a[i],lower_bound返回的是a[i]坐标,否则返回比a[i]大一点的那个元素的坐标),在dp数组中,小于dp[j]而大于dp数组中其他元素的那个元素一定小于a[i]。例如:

12365 :dp[1]=1 dp[2]=2,dp[3]=3,dp[4]=6,dp[5]=0x3f3f3f3f3f3f3f.对于a[5],二分找到的大于等于a[5]的dp[j]=6,j=4

ans=max(ans,j-1+aft[i]),其中j-1+aft[i]=4-1+1=4

123556:dp[1]=1,dp[2]=2,dp[3]=3,dp[4]=4,dp[5]=0x3f3f3f3f3f3f3f.对于a[5],二分找到的大于等于它的dp[j]=5,j=4

ans=max(ans,j-1+aft[i]),其中j-1+aft[i]=4-1+2=5

12367567:dp[1]=1,dp[2]=2,dp[3]=3,dp[4]=6,dp[5]=0x3f3f3f3f3f3f3f.dp[6]=0x3f3f3f3f3f3f3f,dp[7]=0x3f3f3f3f3f3f3f....对于a[5],二分找到的大于等于它的dp[j]=6,j=4

ans=max(ans,j-1+aft[i]),其中j-1+aft[i]=4-1+3=6

代码:

#include<cstdio>
#include<cstring>
#include<string>
#include<string.h>
#include<stack>
#include<algorithm>
#include<iostream>
#include<math.h>
#define maxn 200008
#define ll long long
#define RPG(i,a,b) for(int i=(a);i<(b);i++)
using namespace std;
int aft[maxn],pre[maxn];
ll dp[maxn],a[maxn];

int main()
{
    int T;
    scanf("%d",&T);
    int n;
    while(T--)
    {
        scanf("%d",&n);
        RPG(i,0,n)
        scanf("%lld",&a[i]);
        pre[0]=1;
        RPG(i,1,n)
        {
            if(a[i]>a[i-1])
                pre[i]=pre[i-1]+1;
            else
                pre[i]=1;
        }
        aft[n-1]=1;
        for(int i=n-2; i>=0; i--)
        {
            if(a[i]<a[i+1])
                aft[i]=aft[i+1]+1;
            else
                aft[i]=1;
        }
        int ans=0;
        RPG(i,0,n+5)
            dp[i]=0x3f3f3f3f3f3f3f3f;
        RPG(i,0,n){
            int len=lower_bound(dp+1,dp+n+1,a[i])-dp;
            ans=max(ans,aft[i]+len-1);
            dp[pre[i]]=min(dp[pre[i]],a[i]);
        }
        printf("%d\n",ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/pipitongkw1/article/details/81813166
今日推荐