bzoj 3173 最长上升子序列
来源:互联网 发布:社会发展统计数据库 编辑:程序博客网 时间:2024/06/06 16:32
转:http://blog.csdn.net/d_william/article/details/9146757
题目描述 Description
给定一个序列,初始为空。现在我们将1到N的数字插入到序列中,每次将一个数字插入到一个特定的位置。每插入一个数字,我们都想知道此时最长上升子序列长度是多少?
输入描述 Input Description
第一行一个整数N,表示我们要将1到N插入序列中,接下是N个数字,第k个数字Xk,表示我们将k插入到位置Xk(0<=Xk<=k-1,1<=k<=N)
输出描述 Output Description
N行,第i行表示i插入Xi位置后序列的最长上升子序列的长度是多少。
样例输入 Sample Input
3
0 0 2
样例输出 Sample Output
1
1
2
数据范围及提示 Data Size & Hint
提示
X0等于0 ,我们将1插入到位置0得到序列{1}
X1等于0 ,我们将1插入到位置0得到序列{2,1}
X2等于2 ,我们将1插入到位置0得到序列{2,1,3}数据范围
30%的数据 n<=1000
100%的数据 n<=100000
Analysis
因为数字是从小到大插入的,所以我们可以构造出最终序列,然后O(NlogN)求最长上升子序列。
关键是构造出最终序列。
2B青年:我会平衡树!(我连2B都不如)
平衡树模拟插入,求出最终序列,虽然可以过,但是代码量和时间不尽人意。
下面来讲一下文艺的做法吧...
我们发现,将整个序列反过来做,如果当前数插入的位置定了,将不会再受到影响。
而这样子就可以用树状数组维护,首先将所有的位置都设为一,每次插入一个数,相当于找到最前面的一段区间,它们的和=当前数插入的位置(设为L[1,i]),则这个插入的数的位置就是i。插入之后,将i这个位置置为零(用过了)。
可以通过二分来找到这个i,更好的方法是通过二进制(刚学)。
看下面的代码:
function get(k:longint):longint;var ans,cnt,i:longint;begin ans:=0; cnt:=0; for i:=20 downto 0 do begin ans:=ans+1 shl i; if (ans>=n) or (cnt+c[ans]>=k) then ans:=ans-1 shl i else cnt:=cnt+c[ans]; end; exit(ans+1);end;
这是用树状数组的定义来加速处理的方法,i从20开始取是因为数据范围<=100000(理解不了可以看一下树状数组的定义)。接下来我们就可以还可以再用树状数组维护一个区间最大值,当然直接套O(NlogN)的最长上升子序列的传统做法也可以,不过树状数组比较方便。
上代码:(没看懂)
var i,j,k,n,tmp:longint; c,cnt,pos,ans,fa:array[0..100000] of longint;function getfa(t:longint):longint;begin if fa[t]=t then exit(t); fa[t]:=getfa(fa[t]); getfa:=fa[t];end;function lowbit(x:longint):longint;begin exit(x and (-x));end;function max(a,b:longint):longint;begin if a>b then exit(a) else exit(b);end;procedure change(x,delta:longint);begin while x<n do begin c[x]:=max(c[x],delta); x:=x+lowbit(x); end;end;function getmax(x:longint):longint;begin getmax:=0; while x>0 do begin getmax:=max(getmax,c[x]); x:=x-lowbit(x); end;end;function get(k:longint):longint;var ans,cnt,i:longint;begin ans:=0; cnt:=0; for i:=20 downto 0 do begin ans:=ans+1 shl i; if (ans>=n) or (cnt+c[ans]>=k) then ans:=ans-1 shl i else cnt:=cnt+c[ans]; end; exit(ans+1);end;begin readln(n); for i:=1 to n do begin read(pos[i]); inc(pos[i]); inc(c[i]); if i+lowbit(i)<=n then c[i+lowbit(i)]:=c[i+lowbit(i)]+c[i]; end; for i:=n downto 1 do begin j:=get(pos[i]); cnt[i]:=j; while j<n do begin dec(c[j]); j:=j+lowbit(j); end; end; for i:=1 to n do c[i]:=0; for i:=1 to n do begin tmp:=getmax(cnt[i]-1)+1; ans[i]:=max(ans[i-1],tmp); change(cnt[i],tmp); end; for i:=1 to n do writeln(ans[i]);end.
- bzoj 3173 最长上升子序列
- BZOJ-3173-最长上升子序列
- BZOJ 3173: [Tjoi2013]最长上升子序列
- BZOJ 3173: [Tjoi2013]最长上升子序列
- bzoj 3173: [Tjoi2013]最长上升子序列
- BZOJ 3173: [Tjoi2013]最长上升子序列
- BZOJ 3173 Tjoi2013 最长上升子序列 Treap+树状数组
- BZOJ 3173 [Tjoi2013]最长上升子序列 Treap+LIS
- bzoj 3173: [Tjoi2013]最长上升子序列(splay)
- [Treap] [LIS] BZOJ[3173] [Tjoi2013]最长上升子序列
- 【BZOJ 3591】 最长上升子序列
- 最长上升子序列
- 最长上升子序列
- 最长上升子序列
- 最长上升子序列
- 最长上升子序列
- 最长上升子序列
- 最长上升子序列
- POJ - 2442 Sequence
- Class类和反射
- ora-01555,ORA-22924解决
- ym——Android从零开始(27)(山寨版微信-上)(新)
- How to write software Testing Weekly Status Report
- bzoj 3173 最长上升子序列
- SQL Server死锁总结
- 使用dos 写bat时,使用for循环读取文件中的内容无任何显示
- MySQL CURDATE() 函数
- ym——Android从零开始(27)(山寨版微信-下)(新)
- jQuery Mobile 特性
- 线程安全及不可变性
- 1. WebStorm-The smartest JavaScript IDE 2. Node.js 3. egret
- android -- 小问题 关于ListView设置了OnScrollListener之后onScrollStateChanged()和onScroll方法监听不到的问题