P1020
就是说递减;
一个是要求最长的递减序列长度
对于每个来的导弹,是要选择,到底给已有的系统,还是新起一个系统
如果是贪心的话,就是先看先有的系统能不能拦截,如果能拦截就选差值最小的放进去;如果不能就新起一个系统;
这样不一定是数量最少的,但应该是能找到拦截数量最多的
不对,也不一定,比如原来是一个比较大的数,但是来了个低的,直接就导致后面可能接上的,都接不上了,
那先按照暴力法,就是遍历每个导弹的选择
即导弹来了后,都先后执行给已有系统和新起一个系统,那复杂度将是2^n级别
如果选给已有系统,那就给最接近的系统,然后更新数据
如果新起系统,就向维护系统的数据结构当中插入一个新节点
然后为了加快搜索,维护结构选择搜索树
但是情况数是2^n级别的,每个选择后,对应的树也都不同,复杂度也是非常庞大,一个树是n级别的,那空间复杂度是n*2^n
假设不在乎成本,最后要找的就是2*n中对应的节点最少的树以及2^n中所有的树所有节点里更新次数最多的那一个节点(这个可以在节点结构中保存一个cnt,并在维护中不断更新max,来省掉最后的遍历查找max)
但这个暴力法复杂度完全无法接受,如何优化?
我还没有求解最长非递增子序列的经验,先引导我如何解决这个问题?
说白了就是两个子问题,一个是给定数列的最长非递增自序列,一个是序列中非递增子序列的最少数量
求解最长非递增子序列
那每个导弹的选择,换个语言就是,对于序列中第I个数,以第I个数为结尾时的最长长度,
如果选择以它为结尾,那就是在先有保持的子序列长度再加个1,即cur+1
如果不以它为结尾,那此时的最长长度是dp[i-1]
但如何知道cur?
dp[i]=max(dp[i-1],cur+1)
这个想法不对,因为i所在的序列,它的上一个元素并不一定是i-1,从最优角度就是max(),就是每个dp[i]的确定,都要找一下前面的maxdp,
也不一定就是maxdp,而是满足hi条件的maxdp
这样每个dpi在确定时,都能保证hi<hi-1
设 dp[i] = 以第 i 个导弹(高度 h[i])结尾的最长不升子序列长度,说i就是以i为结尾的最长序列
那结果就是max(dp[i])
那这个说是dp,但其实没想象的那么复杂,还是靠维护多个数据结构维护出来,dp是长度信息,h[i]是高度信息
所以要确定dp[i],N的长度,关键就在于如何查找满足hi条件的maxdp
如果顺序查找,就是n^2复杂度
如果二分查找,就是n*log(n)
这个二分查找,是在查找所有所有满足条件hi条件里的dp的最大值
但并非一次独立的二分查找
假设找到了满足hi条件的序列x,那接下来应该在找x里找对应dp的最大值
但h数组没有单调性,所以也不能二分查找;
用一个数据结构,来维护各个长度下,最好的数值;就是一个数组
那这个数组天然的就是单调递减结构,因为要想让序列长度增加,就必须削减数值;
新元素来的时候,从右向左遍历,找到第一个大于该数值的位置,这样表示元素能插入进去,假设其长度为x,那么插入该元素后,长度变为x+1,那么就需要尝试更新x+1的数值
变为顺序就是,第一个小于该数值的位置上,这样
tail[i]=max(tail[i],h[i])
但是如何利用这个数组知道dp[i]max?
应该是可以的,因为每个元素来了后,去找第一个小于的元素,实际上就是在查找满足hi条件的位置,同时下标的含义还是数组长度,所以也代表了满足条件的最长序列长度,即dpmax
所以最后的最长序列,就是tail的长度
初始化:
先是让tail[0]=h[0]
然后来了新元素后,(由于元素是一个一个来,所以即使更新前面的,也不会对后面的值产生影响)
遍历到tail的尾部
如果当前元素小于h[i]
那么tail[i]=max(tail[i],h[i]),但是都说是小于了,应该也不用取max,就直接是覆盖,tail[i]=h[i]
如果查到最后都没找到,那就新插入一个元素,值为h[i]
求最少的递增序列长度
仿照之前的思想,来了一个元素后,肯定希望往最最接近的序列中插入
以tail[i[,数组下标表示第几个系统,数值代表此时保存的长度
但是这样的贪心思路不一定能找到最优解

就是说去找序列当中,递增序列的最长长度,假设对应的序列为X,那么X当中的每个元素,都会迫使当前系统新增一个设备;因为之前的系统,无论如何也接收不了;
所以只需要去找最长的
如果暴力DP。DPi表示以i为结尾的最长长度,那么hi必须满足大于hj
dp[i]=1+max(dp[j])
如果tail数组优化,tail[i]就是长度为i时,对应的最小数值,这样才能接更多的,那数组天然是递增的;那要找的就是第一个大于的,这样才是由前面的最大小于的元素来的
for
如果大于

求解过程当中,要考虑到等于的情况,
如果等于能接上的话,就是非递增,就是
如果等于不能接上,那就是严格递增,那找条件的时候,就应该是第一个小于等于的
上面就是没考虑等于的情况

就是找在满足条件时的下标用的是顺序遍历,需要用二分法降一降复杂度
二分编写
对于二分的编写,考虑如果数组里元素都不满足时的情况,左侧l和右侧r的值会如何变化,最终值是怎样的
如果写l<r,假设在单调减里找,如果都大于,那么l一直加,
如果要找的元素在最右侧,r的位置始终没动,如果l到r的前一个位置,那么m无法到r的位置,只会是到l,依然不满足条件,那么l+1到r的位置,但是此时就退出循环了;也无法验证最后一个位置了;此时m无法验证n-1位置,最高到n-2
如果都小于,那么r到l前一个位置时,m可以验证l位置,此时返回m是合理的,因为m可以到l,可以验证0的位置;
对于m,其始终,一定会是数组中的某个元素
我上面说的这个是在左闭右闭条件下的情况,m无法验证n-1
但如果是左闭右开,即r=n,而不是n-1的情况
那么l就可以到达最右侧,即n-1的位置,那么m就可以验证n-1
所以此时就消除了除法无法验证最右端的问题
所以一定要用左闭右开
P11680
先是给定LR,先求[1,L]和[1,R]的数量
对于N位长的,
如果为奇数,设N=2k+1,那么自然也包含I<k的所有的首中尾相等数;那么只需要求N所对应的首中尾相等数即可;然后i<k的情况都可以通过组合计数求得
如果为偶数,设N=2k,那么就是求2k-1时,I<k的首中尾相等数,直接组合计数算,不必再求最高位的
对于组合计数计算,如果是2i+1位的数,那么3位,即首中尾是固定相等,占用的,有9种可能;2i+1-3=2i-2尾是自选的,相等于一个2i-2的位数的数,有几种可能,即10^(2i-2)
所以是9*10^(2i-2)
然后就是限制上限的奇数N位上的相等数构造,其首中尾数的下标分别是0,i,2i,设对应上的数字分别是abc
那么就是求abc中,a=b=c所满足的数的数量
对于最高位a,首先对于a-1的数,是随便构造的,即a-1个;
然后对于等于最高位a的情况,就是min(a,b,c)个,所以是a-1+min(a,b,c)个
也不用dfs来遍历构造
dfs(当前位数i,是否紧贴tight,当前相等数字)
1.转为字符串,得到长度N
2.判断N的奇偶
如果是偶数,就是9*10^(2i-2),求和
如果是奇数,就是9*10^(2i-2),求和再加上a-1+min(a,b,c)个
再维护一个数组,表示对于i=0,1,2,3时,不限制上限的取值数量