题目链接:http://acm.csu.edu.cn/csuoj/problemset/problem?pid=1551
升级版:Uva 1471
题意:
让你求删除一段连续的子序列之后的LIS。
题解:
预处理:先求一个last[i],以a[i]为开始的合法最长上升子序列的长度。再求一个pre[i],以a[i]为结尾的合法最长上升子序列长度。
答案应该为
max(以j结束的合法最长上升子序列长度) + 以a[i]为开始的合法最长上升子序列长度。 其中j<a[i]。
1)通过树状数组维护区间最值。
2)通过LIS 维护。(详细请看http://www.cnblogs.com/denghaiquan/p/6761600.html)
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 LOCAL 17 #define eps 0.0000001 18 typedef long long LL; 19 const int inf = 0x3f3f3f3f; 20 const int maxn = 10000+10; 21 const int mod = 1000000007; 22 int a[maxn], pre[maxn], last[maxn], c[maxn]; 23 int n; 24 int lowbit(int x){ 25 return x&(-x); 26 } 27 int ask(int x) 28 { 29 int ans = 0; 30 while(x>0){ 31 ans = max(ans, c[x]); 32 x-=lowbit(x); 33 } 34 return ans; 35 } 36 void updata(int x, int d) 37 { 38 while(x <= 1e4){ 39 c[x] = max (c[x] , d); 40 x += lowbit(x); 41 } 42 } 43 void solve() 44 { 45 int ans = 0; 46 ms(c, 0); 47 for(int i=1;i<=n;i++) scanf("%d", &a[i]); 48 //last[i] 是第i个开始和合法后缀 49 last[n] = 1; 50 for(int i = n-1; i>0;i--){ 51 if(a[i] < a[i+1]){ 52 last[i] = last[i+1] + 1; 53 }else last[i] = 1; 54 } 55 //pre[i] 是第i个结束的合法前缀 56 pre[1] = 1; 57 for(int i=2;i<=n;i++){ 58 if(a[i] > a[i-1]){ 59 pre[i] = pre[i-1] + 1; 60 }else pre[i] = 1; 61 } 62 for(int i=1;i<=n;i++){ 63 ans = max(ans, last[i] + ask(a[i]-1)); 64 updata(a[i], pre[i]); 65 } 66 printf("%d ", ans); 67 } 68 int main() 69 { 70 #ifdef LOCAL 71 freopen("jumping.in", "r", stdin); 72 // freopen("output.txt", "w", stdout); 73 #endif // LOCAL 74 while(~scanf("%d", &n)){ 75 solve(); 76 } 77 return 0; 78 }
升级版,应该数的范围在1e9所以无法用树状数组维护。只能用LIS或者set来维护。