HDU 5489 Removed Interval(2015合肥站网赛1006,DP+树状数组)
2015-09-28 21:18
295 查看
当时写的时候并不会,一直想不通一个问题,每次删除的区间从L,R->L+1,R+1的时候,如何维护整个剩余序列的LIS。太弱。。。。
赛后才搞懂这个问题,就是一个dp的问题吧。
dp1[i]表示以num[i]开头的LIS。
dp2[i]表示以num[i]结尾的LIS。
dp[i]表示以分割出来的第二段num[i]为开头的LIS+第一段中的序列的最大值
我们设删除的区间长度为d
那么dp[i] = dp1[i] + max(dp2[j] | j < i -d && num[j] < num[i])。
因为要在一个logn的复杂度搞定max的查找,那么用线段树就可以搞定了。就是一个普通的LIS过程,复杂度是nlogn。
我们最后要找的答案就是dp[i]的最大值o(n)搞定。
所以这道题最终的复杂度就是nlogn。
注意点:如果删除的区间是从第一个开始或者正好最后一个数结束的时候,那么我们这个区间就是一段了,没有第二段了,这个时候特判一下就好了。
下面附上代码:
赛后才搞懂这个问题,就是一个dp的问题吧。
dp1[i]表示以num[i]开头的LIS。
dp2[i]表示以num[i]结尾的LIS。
dp[i]表示以分割出来的第二段num[i]为开头的LIS+第一段中的序列的最大值
我们设删除的区间长度为d
那么dp[i] = dp1[i] + max(dp2[j] | j < i -d && num[j] < num[i])。
因为要在一个logn的复杂度搞定max的查找,那么用线段树就可以搞定了。就是一个普通的LIS过程,复杂度是nlogn。
我们最后要找的答案就是dp[i]的最大值o(n)搞定。
所以这道题最终的复杂度就是nlogn。
注意点:如果删除的区间是从第一个开始或者正好最后一个数结束的时候,那么我们这个区间就是一段了,没有第二段了,这个时候特判一下就好了。
下面附上代码:
#include <bits/stdc++.h> #define LL long long #define FOR(i,x,y) for(int i = x;i < y;i ++) #define IFOR(i,x,y) for(int i = x;i > y;i --) #define MAXN 100010 using namespace std; int dp[MAXN]; int num[MAXN],con[MAXN]; int c[MAXN]; int cnt,n,d; map <int,int> mat; int lowbit(int x) {return x & (-x);} int Query(int x){ int ans = 0; while(x){ ans = max(ans,c[x]); x -= lowbit(x); } return ans; } void Modify(int x,int val){ while(x <= n){ c[x] = max(c[x],val); x += lowbit(x); } } void init(){ memset(c,0,sizeof(c)); FOR(i,0,cnt){ int val = Query(con[i]-1); dp[cnt-1-i] = val + 1; Modify(con[i],dp[cnt-1-i]); } } int work(){ memset(c,0,sizeof(c)); int ans; ans = (d == cnt) ? 0 : dp[d]; FOR(i,1,cnt){ int r = i + d; if(r > cnt) break; if(r == cnt) { int val = Query(mat[num[i-1]]-1)+1; Modify(mat[num[i-1]],val); int res = Query(n); ans = max(ans,res); break; } int val = Query(mat[num[i-1]]-1)+1; Modify(mat[num[i-1]],val); int res = Query(mat[num[r]]-1) + dp[r]; ans = max(res,ans); } return ans; } int main() { //freopen("test.in","r",stdin); int T,tCase = 0; scanf("%d",&T); while(T--){ printf("Case #%d: ",++tCase); scanf("%d%d",&cnt,&d); FOR(i,0,cnt) scanf("%d",&num[i]),con[i] = num[i]; sort(con,con+cnt); n = 0; mat[con[0]] = ++n; FOR(i,1,cnt) if(con[i] != con[i-1]) mat[con[i]] = ++n; FOR(i,0,cnt) con[i] = n+1-mat[num[cnt-1-i]]; init(); printf("%d\n",work()); } return 0; }
相关文章推荐
- 动态链接过程延迟绑定的实现(PLT)
- 修复ubuntu启动项
- 分页式存储管理方式AND请求分页式存储管理
- POJ-1979 Red and Black(DFS)
- QT如何设置应用程序的图标
- iOS大典之集合视图
- JS校验表单项
- ThinkPHP--后台登录页面搭建
- 卖票模拟多线程
- CSS float浮动的深入研究、详解及拓展(一)
- Reverse Linked List
- ArcGIS学习一 Create a map
- iOS8自适应布局视频教程
- 控制台编程的几个小命令
- Java基础知识强化之IO流笔记07:自定义的异常概述和自定义异常实现
- 【欧拉路径(有向图)】poj 1386 play on words
- android项目R文件丢失问题
- spark本地运行模式
- GsonFormat快速实现JavaBean
- Android之Handler的postDelayed()使用方法