题目链接:http://acm.csu.edu.cn/csuoj/problemset/problem?pid=1551
题意:
给出一段序列, 删除其中一段连续的子序列(或者不删), 使得剩下的序列的最长上升连续子序列最大。
题解:
1.对于要删除的的子序列而言,要么夹在答案序列中间,要么在外面(删与不删对答案都没影响)。所以总体而言,答案序列被分成左右两半。
2.用SL[i]记录从左边起以a[i]为结尾的最长上升连续子序列的长度, SR记录从右边起以a[i]为开始的最长上升连续子序列的长度。
3.枚举SR[i],用线段树找出最大的SL[x](x的下标小于i),即SL[x]和SR[x]构成一段完整的序列, 期间一直更新线段树。
学习之处:
1.线段树/树状数组的动态使用,即边查询边更新。
类似的题: http://blog.csdn.net/DOLFAMINGO/article/details/65643894
2.RMQ/线段树/树状数组的静态使用,即build()之后值进行查询操作。
相关的题:http://blog.csdn.net/DOLFAMINGO/article/details/68953809 http://blog.csdn.net/dolfamingo/article/details/70306529
线段树:
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cstdlib> 5 #include <string> 6 #include <vector> 7 #include <map> 8 #include <set> 9 #include <queue> 10 #include <sstream> 11 #include <algorithm> 12 using namespace std; 13 #define pb push_back 14 #define mp make_pair 15 #define ms(a, b) memset((a), (b), sizeof(a)) 16 #define eps 0.0000001 17 typedef long long LL; 18 const int INF = 2e9; 19 const LL LNF = 9e18; 20 const int mod = 1e9+7; 21 const int maxn = 10000+10; 22 23 int a[maxn], SL[maxn], SR[maxn], MAX[maxn<<2]; 24 int n; 25 26 void update(int rt, int l, int r, int pos) 27 { 28 if(l==r) 29 { 30 MAX[rt] = max(MAX[rt], SL[pos]); 31 return; 32 } 33 34 int mid = (l+r)>>1; 35 if(a[pos]<=mid) update(rt*2, l, mid, pos); 36 else update(rt*2+1 ,mid+1, r, pos); 37 38 MAX[rt] = max(MAX[rt*2], MAX[rt*2+1]); 39 } 40 41 int query(int rt, int l, int r, int x, int y) 42 { 43 if(x<=l && y>= r) 44 return MAX[rt]; 45 46 int mid = (l+r)>>1, ret = 0; 47 if(x<=mid) ret = max(ret, query(rt*2, l, mid, x, y)); 48 if(y>=mid+1) ret = max(ret, query(rt*2+1, mid+1, r, x, y)); 49 return ret; 50 } 51 52 void solve() 53 { 54 for(int i = 1; i<=n; i++) 55 scanf("%d",&a[i]); 56 57 SL[1] = SR[n] = 1; 58 for(int i = 2; i<=n; i++) 59 SL[i] = (a[i]>a[i-1]?SL[i-1]+1:1); 60 for(int i = n-1; i>0; i--) 61 SR[i] = (a[i]<a[i+1]?SR[i+1]+1:1); 62 63 int ans = 0; 64 for(int i = 1; i<=n; i++) 65 { 66 int tmp = 0; 67 if(a[i]>1) tmp = query(1, 1, 10000, 1, a[i]-1); 68 69 ans = max(ans,SR[i]+tmp); 70 update(1, 1, 10000, i); 71 72 } 73 printf("%d ",ans); 74 } 75 76 int main() 77 { 78 while(scanf("%d",&n)!=EOF) 79 { 80 ms(SL,0); 81 ms(SR,0); 82 ms(MAX,0); 83 solve(); 84 } 85 }
树状数组:
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cstdlib> 5 #include <string> 6 #include <vector> 7 #include <map> 8 #include <set> 9 #include <queue> 10 #include <sstream> 11 #include <algorithm> 12 using namespace std; 13 #define pb push_back 14 #define mp make_pair 15 #define ms(a, b) memset((a), (b), sizeof(a)) 16 #define eps 0.0000001 17 typedef long long LL; 18 const int INF = 2e9; 19 const LL LNF = 9e18; 20 const int mod = 1e9+7; 21 const int maxn = 10000+10; 22 23 int a[maxn], SL[maxn], SR[maxn], c[maxn]; 24 int n; 25 26 int lowbit(int x) 27 { 28 return x&(-x); 29 } 30 31 void add(int x, int d) 32 { 33 while(x<maxn) 34 { 35 c[x] = max(c[x],d); 36 x += lowbit(x); 37 } 38 } 39 40 int sumc(int x) 41 { 42 int s = 0; 43 while(x>0) 44 { 45 s = max(s,c[x]); 46 x -= lowbit(x); 47 } 48 return s; 49 } 50 51 void solve() 52 { 53 for(int i = 1; i<=n; i++) 54 scanf("%d",&a[i]); 55 56 SL[1] = SR[n] = 1; 57 for(int i = 2; i<=n; i++) 58 SL[i] = (a[i]>a[i-1]?SL[i-1]+1:1); 59 for(int i = n-1; i>0; i--) 60 SR[i] = (a[i]<a[i+1]?SR[i+1]+1:1); 61 62 int ans = 0; 63 for(int i = 1; i<=n; i++) 64 { 65 int tmp = 0; 66 if(a[i]>1) tmp = sumc(a[i]-1); 67 68 ans = max(ans,SR[i]+tmp); 69 add(a[i],SL[i]); 70 71 } 72 printf("%d ",ans); 73 } 74 75 int main() 76 { 77 while(scanf("%d",&n)!=EOF) 78 { 79 ms(SL,0); 80 ms(SR,0); 81 ms(c,0); 82 solve(); 83 } 84 }