HDU 5489(2015 Asia Regional Hefei Online F )

【題目鏈接】
http://acm.hdu.edu.cn/showproblem.php?pid=5489

【解題報告】
題目大意是,在數組A中,刪去連續的L個數之後的最長上升子序列(LIS)。

爲了解決這道題目,我們先來看LIS的nlogn求法:

1.維護一個單調遞增序列LIS

2.對每個點A[i],找到LIS裏大於等於它的第一個位置,嘗試把它插入到序列裏第x個位置。(二分查找)
那麼dp[i]表示0..i的序列,以i爲末位的最長上升子序列。顯然dp[i]=x

3.如果A[i]<LIS[x]那麼把LIS[x]更新爲A[i]繼續向後更新。
4.ans=max{  dp[i] }

這個算法的時間複雜度顯而易見是O( nlogn )的。

之後來看這道題目。這時候算法已經很清楚了。
對每個i,我們求把它放在0…i-L這個序列後的LIS,這個維護方法是,每次我們掃到一個a[i],把a[i-L]插入到LIS裏。
這時候我們還需要求i..N的LIS,這個很簡單,倒過來求一次LIS即可。
最後我們求得每個i的LIS,取最大值即可。
時間複雜度是O( nlogn )。

【參考代碼】

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

const int INF=1e9;
const int maxn=1e5+50;

int N,L;
int a[maxn],b[maxn];
int LIS[maxn];
int dp[maxn];

int main()
{
      int T,kase=0;
      cin>>T;
      while(T--)
      {
            scanf("%d%d",&N,&L);
            for( int i=0; i<=maxn; i++ )  LIS[i]=INF;

            memset ( dp,0,sizeof dp );

            for( int i=0; i<N; i++ )
            {
                  scanf( "%d",&a[i] );
                  b[i]=-a[i];
            }

           for( int i=N-1; i>=0; i--  )
           {
                 int pos=lower_bound(   LIS, LIS+N, b[i] )-LIS;
                 if(  b[i]<LIS[pos] )LIS[pos]=b[i];
                 dp[i]=pos+1;
           }
           for( int i=0; i<=maxn; i++ )  LIS[i]=INF;

            int ans=0;
           for(  int i=L; i<N; i++ )
           {
                  int pos=lower_bound(  LIS, LIS+N, a[i] )-LIS;
                  ans=max(   ans, dp[i]+pos );
                  pos=lower_bound(  LIS, LIS+N, a[i-L] )-LIS;
                  LIS[pos]=a[i-L];
                  if(  i==N-1 )   //刪去最後的L元素
                  {
                        int pos=lower_bound( LIS, LIS+N,  a[i-L] )-LIS;
                        ans=max(  ans,   pos+1 );
                  }
           }
           printf(   "Case #%d: %d\n",++kase, ans  );
      }

      return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章