一些优秀的解题思路

1.妙用二分:有N个数,任取两个数组合,共有N*(N-1)种组合,问其中第K大的和是多少?

思路:从第 -1e18 到 1e18 去二分,每次二分的判断条件为 当前大于mid的数是否小于k 

复杂度:N*lgN*lgN


2.基础线段树修改:每次对区间内的每一个数 进行下取整 ,每次询问区间和是多少?

思路:分析一下 一段递增的序列 下取整之后 是单调不递减(具有周期性) 1 2 3 4 5 6 7 对 3下取整之后变为 0 0 1 1 2 2 因此他们的变化量也是 一个单调不递减 相等时候 为边界:2 3 2/3=0 3/3=1 同时2与3同时加了1,所以说我们可以根据这一个优化点去判断,如果一个区间内的最大值与最小值的变化量相同 :那么这一个区间的变化都相同 例如:2 3 3 3 3 对3下取整 0 1 1 1 1 相当于对一个区间都减了2,所以我们根据这个条件去优化(因为没有什么能够继续优化的了) ,就将区间除法->区间加法。同时维护一个最大值与最小值即可。

复杂度:比较玄学 如果相邻数字较多趋于 nlgn


3.贪心:多任务调度: 有n台洗衣机,m台烘干机,每台机器只能同时运转一件衣服,n台洗衣机的时间分别为a_i,m台烘干机分别的时间为 b_i,问最少需要多久烘干P件衣服?

碰到过很多贪心,一直没总结果,从这题以后 就会总结到这个博客里。

是一个多任务调度的题目:

1.首先洗衣服和烘干两个操作分开,所以我们分别对两个操作进行考虑,又因为烘干要在洗衣服之后 ,所以我们需要先处理出 洗衣服的最短时间是多少,所以首先处理一下,第i件衣服洗完最早需要多久,那么怎么去维护这个值呢?我们可以用优先队列去维护这个衣服要给哪台洗衣机选,也就是选哪台洗衣机可以让时间更早的结束(因为我要尽可能的时间少),选择完以后呢,再把当前这个洗衣机的状态更新,其实就是 结束时间+a_i,代表下次再用这台洗衣机结束时间即为 t+a_i.

2.之后对于烘干的操作来说,洗衣服操作已经明确说明不可以再早了,那么洗完最后一件衣服,烘干的时间要尽可能的短,那么此时,还是维护一个思路一样的优先队列。该优先队列表示,如果选择了这台烘干机,那么总的烘干时间+等待时间为多少,其实也就是:在启用这台烘干机之前他执行的时间——等待时间+烘干时间,同样的用完之后将更新后的放到优先队列中

最后取一个总时间的最大值 ans=max(ans,最早开始时间+最少烘干与等待时间)

复杂度 :nlogn+plogn


4.Floyd变式:N个点,每到一个点可以选择加满油或者不加油,给出M条双向路径,经过这条路径会减少油量,最多可以携带m升油Q次询问,每次询问 从X到Y最少需要加几次油才可以到达?

Floyd变式,首先将 全源最短路预处理出来,之后根据处理出来的最短路,新建一个图:如果x到y的最短路小于等于m,那么表明:x点装满一次油就可以到达y点,那么设[x,y]的距离为1。在新图的基础上继续跑一个最短路,就可以得到 任意点间的最短的油耗。

总结适用类型:

1.N小于等于300时可以考虑,若大于300,在小于1000的情况下 Jason全源最短路应该可以行得通

2.多限制问题,可以将多层限制转换为一层限制:x->y距离小于油耗那么一定可以加一次油到达,如果这里有剩余还能到达其他点,那么从x绝对也可以到达其他点,因为x->y+y->z一定小于等于m。

3.新建图的权值与最短路有关 比如路程对应花费


5.离散化差分:假设有N个仓库,M次操作,每次选择[l,r]区间内的仓库 投放种类为p的货物,输出最后每个仓库内各有多少种货物?

1.这类题目非常好,首先考虑用什么去维护这个区间操作呢?因为每次加的货物又不相同我们肯定可以利用一个 位置+种类的二维数组去维护,没到一个点看一看当前点的种类>1的有多少个。但是种类太多,二维数组肯定开不出来。这时候就需要离散化处理一下。

2.根据差分的性质 区间[l,r]内,增加一个种类p,相当于f[l][p]++,f[r+1][p]--。维护一个种类数和一个map记录的种类数量,对于每一个点的操作 无非就是将该加的加上,该减的减去。那么这样维护的话(用一个两个vector记录一下 加和减的情况),只需要判断如果增加的时候发现之前没有这个种类,那么此时种类数就需要++,或者减少的时候发现当前种类只剩1了,那么此时这个点的种类就会--。

3.最后会发现全局总类p 就是答案

总结使用类型:

1.静态区间修改,动态 ——暂时搞不定

2.询问每个点的种类数而且是叠加的不是覆盖的。

变式思考:

单点多少个货物?或者区间内多少个货物?——线段树or树状数组

区间内的种类数(种类都不一样)——树状数组

区间内的种类数(种类存在一样)——暂时搞不定

区间内不同数字的个数——主席树维护位置or 莫队(记录之前数字) 

区间内一个数字的出现次数最多出现m次,问最多选多少个数字——与上题一样维护前i-m的位置出现的情况


6.LIS的深入理解: 给定一段序列 长度为n,你需要输出n个数,代表删除第i个数之后的LIS长度为多少?

1.首先考虑维护一个数组dp[i],表示以a[i]为结尾的最长的非下降子序列的长度。

2.从后向前遍历,维护一个r[i]代表长度为i结尾的最大元素是多少,所以如果当前a[i]<=r[dp[i]+1] 则说明 a[i]在LIS中的第i个位置。

然后用a[i] 去更新 r[dp[i]]。(以上也肯定可以推出 r[len+1]=INF,初始长度+1=INF)

3.补充一下,为什么a[i]<=r[dp[i]+1]时,可以确定他的位置:LIS是连续不下降的,我们从后往前遍历,如果说对于当前长度为x的,如果后面长度为x+1>=x ,说明这个可以成为第x个元素与第x+1个元素联立,这也是为什么从后往前维护的原因,因为从后往前维护一定可以保证 最终长度的结尾是LIS的长度1

7.贪心套路:N个装置,每个装置有位置pos[i],炸弹控制范围[pos-D,pos+D],杀伤力de[i],耐久度p[i],问最少启动多少次炸弹(任意位置)可以使所有装置全部损坏(耐久度小于0)?

1.经典贪心套路,从左到右看每一个装置,对于最左边的装置是一定需要炸的,怎么让在炸掉最左边的同时使得他对答案的贡献最优呢?

2.答案就是在pos+D位置启用炸弹,这样炸弹的控制范围就可以达到pos+2D,剩下的就用树状数组或者线段树动态维护一下就好了.

8.贪心套路:
在一个游戏中,需要在n个士兵中选出一些士兵组成一个团去打副本。第i个士兵的战力为v[i],团的战力是团内所有士兵的战力之和。但是这些士兵有特殊的要求:如果选了第i个士兵,这个士兵希望团的人数不超过s[i]。(如果不选第i个士兵,就没有这个限制。)tokitsukaze想知道,团的战力最大为多少。

可以考虑枚举选多少个人:

首先选择k个人的话,我们的目标就是要从大于等于限制数大于等于k的士兵中找出,最大的k个

所以首先根据每个人的容量限制从大到小排序,之后用优先队列维护前k大的权值之和,也就说如果当前q.size()大于k,要减去当前k个中权值最小的几个使得q.size()==k。这样就解决了这个问题。

总结:逆向思维考虑,优先队列维护最小值然后外界变量记录最大值。

To be Continue

发布了157 篇原创文章 · 获赞 146 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/qq_43857314/article/details/104383834