【转】关于LIS和一类可以用树状数组优化的DP 预备知识

原文链接 http://www.cnblogs.com/liu-runda/p/6193690.html

  1. 预备知识

    DP(Dynamic Programming):一种以无后效性的状态转移为基础的算法,我们可以将其不严谨地先理解为递推。例如斐波那契数列的递推求法可以不严谨地认为是DP。当然DP的状态也可以是二维/三维的,某一维的含义也不仅仅是指某个数列的第几项。

    树状数组(BIT or fenwick tree):一种高效地动态维护一个序列并动态求取前缀和的数据结构。修改某个元素/求一次前缀和的时间复杂度均为O(logn)

  2 LIS

    好了现在假设你们都会打树状数组了(如果不会的话,baidu一发吧!顺便把线段树也自学了吧!如果学不会树状数组只把线段树自学了也成因为好像并没有树状数组能干而线段树干不了的事情),让我们做一道例题练习一下吧!。

    给出一个长度为n的序列,求LIS长度(LIS,longest increasing sequence,最长上升子序列,子序列定义为从原序列取出的一些未必相邻但保持原先的相对顺序的数,上升子序列满足子序列中前一个数严格小于后面的数)

    50% n<=5000,100% n<=50000

    50%的数据其实并没有用到树状数组。

    O(n^2)的LIS算法:定义f[i]为强制以第i项结尾时的LIS长度。那么从1到n依次求出每个f[i],f[i]可以由f[1...i-1]推出。

    好了,现在假设你们都会写50分了。我们考虑把算法优化到能跑50000

    首先离散化,将原先的数字对应到1-tot(tot为出现过的数值种类),例如10,10,20,15变成1,1,3,2

    那么我们定义g[i]为以数值i结尾的LIS长度,并从左向右扫描原数组,同时维护g数组。扫描1,1,3,2时,g数组变化如下:(未出现的项的值为0)

      a.g[1]=1

      b.g[1]=1

      c.g[1]=1,g[3]=2

      d.g[1]=1,g[2]=2,g[3]=2

    YY一下我们怎样用g数组完成DP。

    接下来我们需要一种数据结构支持单点修改(只增不减)和前缀最大值查询。

    首先来一个逗比分块写法维护g数组:将g均分成sz块,维护每一块的最大值。修改可以O(1)完成,前缀最大值查询可以将整块整块的部分用每一块的最大值求,零散部分暴力扫一遍。sz取在sqrt(n)附近的时候效率最高。总时间复杂度O(nsqrt(n)),自信AC。

    如果n<=233333?

    我们可以树状数组维护g数组。原始的树状数组改造后可以支持单点修改(只增不减)和前缀最大值查询。把树状数组的加法换成取最大值,YY一下。

    最后整个g数组的最大值就是答案。

  3. LCS

    好了,现在假设你们都会nlogn的LIS,让我们来一道例题练习一下吧!

    uva10635 Prince and Princess(数据范围是我口胡的)

    给出两个1~n的排列(一个1~n的排列中,1-n每个数字出现一次,不重复出现),求LCS(最长公共子序列)长度。50%的数据保证第一个排列为1,2,3,...n按顺序递增的。

    n<=233333

    50%数据是第二个排列的LIS。很好50分到手。

    下面设想一下,把数字重新编号,LCS长度不变。例如,两个序列为1,2,3; 3,2,1.那么a,b,c;c,b,a的答案是和它一样的。那么把数字编号为数字也是可以的。

    例如这两个数据:

    (1)

    4

    1 2 3 4

    2 3 4 1

    (2)

    4

    4 3 2 1

    3 2 1 4

    它们的答案是相同的。因为在求解LCS时,我们只关注两个序列某两个下标处的数值是否相同,重新编号没有改变“对应下标位置的数相同”的信息。

    那么我们把一个序列重编号为1,2,3...n,对另一个序列也用同样的对应关系重编号(即把第二个序列中每个数改成这个数在第一个序列中出现的下标),跑LIS,自信AC。

  4. more about LCS

    接下来我们分兵奇袭,用另一条思路得出刚才例题lcs的另一个nlogn做法。

    首先自己yy一下LCS的O(n^2)算法。它的状态定义为f[i][j]表示允许使用第一个序列的前i个元素,第二个序列的前j个元素(其中第i个,第j个元素不要求必须使用)

    接下来我们修改状态定义(这种事情在优化DP时需要经常干)使得它能优化到nlogn.

    新的状态中,f[i][j]表示允许使用第一个序列的前i个元素,第二个序列的前j个元素(其中第一个序列第i个元素不必须使用,第二个序列第j个元素必须使用

    于是我们把原先的DP改成分层的过程,考虑从f[i-1][]求出f[i][],那么这两个数组最多有一个位置不同(只有以第一个序列的第i个元素结尾的答案会发生改变)。

    那么我们动态维护这个数组就可以了。假如第一个序列中第i个元素在第二个序列中出现在第k个位置,那么修改f[k]即可(这里已经干掉了第一维)。

    f[k]等于什么?等于f[1...k-1]的最大值+1,因为在LCS中前一项一定是第二个序列前面k-1的项中的一项(如果已经是第一项,没有前一项?边界自己处理一下我就不(懒得)写了)。

    于是还是树状数组前缀最大值,只增不减的单点修改。

    事实上,这个算法只要保证匹配上的位置不多即可。因此1-n每个数字出现5次也是能写的。

    http://www.lydsy.com/JudgeOnline/problem.php?id=1264 bzoj1264基因匹配

  5。more about BIT&DP

    二维树状数组也是可以拿来优化DP的 http://www.lydsy.com/JudgeOnline/problem.php?id=3594  方伯伯的玉米田

    坐标系可以转...http://www.lydsy.com/JudgeOnline/problem.php?id=2131  免费馅饼

    和树状数组没关系的傻逼题 http://www.lydsy.com/JudgeOnline/problem.php?id=4300

    2016.12.31update:终于想到了一道noip题NOIP2012摆花 http://cogs.pro/cogs/problem/problem.php?pid=1270

  6. 巩固练习一下LIS

    http://www.lydsy.com/JudgeOnline/problem.php?id=3173

    http://www.lydsy.com/JudgeOnline/problem.php?id=4660

由于我太弱,所以这里的例题比较少...虚心求dalao们在评论区提供例题。

时间: 2024-07-30 13:39:54

【转】关于LIS和一类可以用树状数组优化的DP 预备知识的相关文章

[noip科普]关于LIS和一类可以用树状数组优化的DP

预备知识 DP(Dynamic Programming):一种以无后效性的状态转移为基础的算法,我们可以将其不严谨地先理解为递推.例如斐波那契数列的递推求法可以不严谨地认为是DP.当然DP的状态也可以是二维/三维的,某一维的含义也不仅仅是指某个数列的第几项. 树状数组(BIT or fenwick tree):一种高效地动态维护一个序列并动态求取前缀和的数据结构.修改某个元素/求一次前缀和的时间复杂度均为O(logn) 2 LIS 好了现在假设你们都会打树状数组了(如果不会的话,baidu一发吧

HDU - 5542 The Battle of Chibi(LIS+树状数组优化)

The Battle of Chibi Cao Cao made up a big army and was going to invade the whole South China. Yu Zhou was worried about it. He thought the only way to beat Cao Cao is to have a spy in Cao Cao's army. But all generals and soldiers of Cao Cao were loya

Codeforces 909 C. Python Indentation (DP+树状数组优化)

题目链接:Python Indentation 题意: Python是没有大括号来标明语句块的,而是用严格的缩进来体现.现在有一种简化版的Python,只有两种语句: (1)'s'语句:Simple statements. 相当于一般语句.(2)'f'语句:For statements. 相当于for循环,并且规定它的循环体不能为空. 然后给你一段没有缩进的Python程序,共n行(n <= 5000).问你添加缩进后,有多少种合法且不同的Python程序. 题解:题目解析 DP过去,如果第i个

HDU 6240 Server(2017 CCPC哈尔滨站 K题,01分数规划 + 树状数组优化DP)

题目链接  2017 CCPC Harbin Problem K 题意  给定若干物品,每个物品可以覆盖一个区间.现在要覆盖区间$[1, t]$. 求选出来的物品的$\frac{∑a_{i}}{∑b_{i}}$的最小值. 首先二分答案,那么每个物品的权值就变成了$x * b_{i} - a_{i}$ 在判断的时候先把那些权值为正的物品全部选出来, 然后记录一下从$1$开始可以覆盖到的最右端点的位置. 接下来开始DP,按照区间的端点升序排序(左端点第一关键字,右端点第二关键字) 问题转化为能否用剩

HDU 6447 - YJJ&#39;s Salesman - [树状数组优化DP][2018CCPC网络选拔赛第10题]

Problem DescriptionYJJ is a salesman who has traveled through western country. YJJ is always on journey. Either is he at the destination, or on the way to destination.One day, he is going to travel from city A to southeastern city B. Let us assume th

LUOGU P2344 奶牛抗议 (树状数组优化dp)

传送门 解题思路 树状数组优化dp,f[i]表示前i个奶牛的分组的个数,那么很容易得出$f[i]=\sum\limits_{1\leq j\leq i}f[j-1]*(sum[i]\ge sum[j-1])$,但是这样的时间复杂度是$O(n^2)?$,所以考虑优化,发现必须满足$sum[i]\ge sum[j-1]?$才能进行转移,那么直接离散化后用树状数组维护一个前缀和即可. #include<iostream> #include<cstdio> #include<cstr

HDU 5542 - The Battle of Chibi - [离散化+树状数组优化DP]

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5542 Problem DescriptionCao Cao made up a big army and was going to invade the whole South China. Yu Zhou was worried about it. He thought the only way to beat Cao Cao is to have a spy in Cao Cao's army.

LIS 树状数组优化

lis 众所周知 即最长上升子序列 可以用dp求解 复杂度O(n^2) 我们考虑优化 用树状数组(或者线段树) 树状数组维护区间最大值 (省去原始O(n^2)算法中的查找) 这样还能求出以i结尾的lis 二分只能求出当前序列的lis (许多题里要求lis个数什么的qwq 总之比二分方便 除了码量长) 还有一个小点就是可能会用到离散化(传送门) 具体实现看代码 #include<bits/stdc++.h> using namespace std; int a[mxn],b[mxn],n,sz,

bzoj3594: [Scoi2014]方伯伯的玉米田--树状数组优化DP

题目大意:对于一个序列,可以k次选任意一个区间权值+1,求最长不下降子序列最长能为多少 其实我根本没想到可以用DP做 f[i][j]表示前i棵,操作j次,最长子序列长度 p[x][y]表示操作x次后,最高玉米为y时的最长子序列长度 那么以n棵玉米分阶段,对于每个阶段 f[i][j]=max{p[k][l]}+1,  其中k=1 to j , l=1 to a[i]+j 然后用树状数组维护p[][]的最大值 1 #include<stdio.h> 2 #include<string.h&g