動態規劃入門 COGS1398 最長上升子序列
阿新 • • 發佈:2019-02-02
1398. 最長上升子序列
★ 輸入檔案:lis1.in
輸出檔案:lis1.out
簡單對比
時間限制:1 s 記憶體限制:256 MB
【題目描述】
設有整數序列A[1],A[2],A[3],…,A[m],若存在下標i1<i2<i3<…<in,且A[i1]<A[i2]<A[i3]<…<A[in],則稱 序列A[1],A[2],A[3],…,A[m]中有長度為n的上升子序列A[i1] , A[i2] ,A[i3] ,…,A[in]。
請程式設計計算指定序列的最長上升子序列長度。
【輸入格式】
第一行一個正整數n(n<1001),表示序列中整數個數;
第二行是空格隔開的n個整陣列成的序列。
【輸出格式】
一個正整數,表示輸入檔案中整數序列的最長上升子序列的長度。
【樣例輸入】
7
1 7 3 5 9 4 8
【樣例輸出】
4
【樣例說明】
j
i
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<algorithm> 5 using namespace std; 6 7 int n; 8 int in[10010],f[10010]; 9 int ans; 10 11 int main(){ 12 scanf("%d",&n); 13 for(int i=1;i<=n;i++) scanf("%d",&in[i]),f[i]=1; 14 for(int i=2;i<=n;i++){ 15 for(int j=1;j<i;j++) 16 if(in[i]>in[j]) f[i]=max(f[i],f[j]+1); 17 ans=max(ans,f[i]); 18 } 19 printf("%d",ans); 20 return 0; 21 }
單調棧優化
從前向後掃描序列列,維護一個單調棧
插⼊入一個數時,我們在h[] 中二分出一個位置i,使得h[i]<a[k+1]<=h[i + 1],令h[i+1]=a[k + 1] 即可
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 7 int n; 8 int num[10010]; 9 int top; 10 int tmp; 11 12 void add(int t){ 13 if(t>num[top]) num[++top]=t; 14 else{ 15 int ll=1; 16 int rr=top; 17 int mid; 18 while(ll<=rr){ 19 mid=(ll+rr)>>1; 20 if(t>num[mid]) ll=mid+1; 21 else rr=mid-1;//注意-1和+1 22 } 23 num[ll]=t; 24 } 25 return; 26 } 27 28 int main(){ 29 scanf("%d",&n); 30 num[0]=-1; 31 for(int i=1;i<=n;i++) scanf("%d",&tmp),add(tmp); 32 printf("%d",top); 33 return 0; 34 }
樹狀陣列優化
陣列離散化並用樹狀陣列維護字首最大值
1 //實為最長上升子序列 2 #include<iostream> 3 #include<cstdio> 4 #include<cstring> 5 #include<algorithm> 6 using namespace std; 7 8 int n; 9 int in[10010],val[10010]; 10 int len; 11 int b[10010];//b[i]以數字i結尾的子序列最長可以為的值 12 //掃描到in[k]這個位置時,b[i]中只有b[a[k]]會改變 13 //b[a[k]]=max(b[i]+1|i<a[k]) 14 int ans,temp; 15 16 void add(int v,int pos){ 17 for(int i=pos;i<=len;i+=i&(-i)) b[i]=max(v,b[i]); 18 return; 19 } 20 21 int ask(int pos){ 22 int t=0; 23 for(int i=pos;i;i-=i&(-i)) t=max(t,b[i]); 24 return t; 25 } 26 27 int main(){ 28 scanf("%d",&n); 29 for(int i=1;i<=n;i++) scanf("%d",&in[i]),val[i]=in[i]; 30 sort(val+1,val+n+1); 31 len=unique(val+1,val+n+1)-val;//去重 保證最長上升 32 memset(b,0,sizeof(b)); 33 ans=1; 34 for(int i=1;i<=n;i++){ 35 in[i]=lower_bound(val+1,val+len+1,in[i])-val+1;//離散化???高大上 36 temp=ask(in[i]-1)+1; 37 ans=max(ans,temp); 38 add(temp,in[i]); 39 } 40 printf("%d",ans); 41 }
線段樹優化
可以用樹狀陣列優化,那麼顯然可用線段樹
然而我碼了2K掛掉了,以後再補