1. 程式人生 > >C-勤奮的楊老師 (dp應用+二分)

C-勤奮的楊老師 (dp應用+二分)

時間限制:C/C++ 1秒,其他語言2秒
空間限制:C/C++ 32768K,其他語言65536K
64bit IO Format: %lld

題目描述 

楊老師認為他的學習能力曲線是一個拱形。勤奮的他根據時間的先後順序羅列了一個學習清單,共有n個知識點。但是清單中的知識並不是一定要學習的,可以在不改變先後順序的情況下有選擇的進行學習,而每一個知識點都對應一個難度值。楊老師希望,後學習的知識點的難度一定不低於前一個知識點的難度(i<j時ai<=aj),而可能存在一個臨界點,在臨界點以後,他希望後學習的知識點的難度一定不高於前一個知識點的難度(i<j時ai>=aj)。楊老師想盡可能多的學習知識。請問:楊老師最多可以學習多少知識?

輸入描述:

第一行:一個整數n(0<n<500000)接下來一行:n個整數,第i個整數ai(0<=ai<500000)表示第i道題目的難度。

輸出描述:

一行一個整數,表示楊老師最多可以學習多少個知識。

示例1

輸入

5
1 4 2 5 1

輸出

4

題意:對於某個位置,求前部分的最長上升子序列長度與後部分最長上升子序列長度的和的最大值.

開四個陣列,前兩個陣列分別儲存的是前,後部分的最長上升子序列.後兩個陣列儲存的是前,後部分的最長上升子序列長度

最後再暴力走一遍,總的時間複雜度為O(nlogn).

#include<bits/stdc++.h>
using namespace std;
int dp1[500010],dp2[500010],d1[500010],d2[500010],a[500010],n;
void my_solve()
{
    int s=0;
    fill(dp1,dp1+n,INT_MAX);
    fill(dp2,dp2+n,INT_MAX);
    for(int i=0;i<n;i++)
    {
        int k=upper_bound(dp1,dp1+n,a[i])-dp1;
        dp1[k]=a[i];
        d1[i]=k+1;
    }
    for(int i=n-1;i>=0;i--)
    {
        int k=upper_bound(dp2,dp2+n,a[i])-dp2;
        dp2[k]=a[i];
        d2[i]=k+1;
    }
    for(int i=0;i<n;i++)
        s=max(s,d1[i]+d2[i]-1);
    printf("%d\n",s);
}
int main()
{
    scanf("%d",&n);
    for(int i=0;i<n;i++)
        scanf("%d",&a[i]);
    my_solve();
    return 0;
}