NOIP训练营集训笔记—信息学基础算法(倍增与分治算法

 

本文摘自清北OI学堂内部笔记,作者潘恺璠,来自柳铁一中曾参加过清北训练营提高组精英班,主要记录的是信息学基础算法。笔记非常详细,特分享给大家! NOIP2019年夏令营正在报名中,6大校区10种班型,可前往微信noipnoi报名!

一、倍增算法:

定义:用f[i][j]表示从i位置出发的2j个位置的信息综合(状态)

一个小小的问题:为什么是2j而不是3j,5j,…?因为,假设为kj,整个算法的时间复杂度为(k-1)logk,当k=2时,时间复杂度最小。

这个算法的三个应用:

1.倍增ST表:

应用:这个ST表是用来解决RMQ问题(给你n个数,m次询问,每次询问[l,r]这个区间的最大值),当然,解决RMQ问题是可以用线段树来做的,但是比较麻烦,NOIP 80%是不会用线段树来做,还是用ST表方便。

定义:f[i][j]表示:从i到i+2j-1这2j个位置的元素最大值

初始化:f[i][0]=z[i](第i个位置到第i+20-1个位置的最大值,对应只有一个元素的区间)

转移:f[i][j]=max(f[i][j-1],f[i+2(j-1)][j-1]) (把[i,i+2j-1]这个区间分治为两个区间,这两个区间拼在一起就成了原来一个大的区间,两个区间长度都为2j-1)

//建立ST表,引自P2O5 dalao的blog:https://zybuluo.com/P2Oileen/note/816892#应用1-st表

for(int a=1;a<=n;a++) f[a][0]=z[a];//z[]为源数据区间数组 

for(int j=1;j<=logn;j++)

{

    for(int i=1;i+z^j-1<=n;i++)

        f[i][j]=max(f[i][j-1],f[i+2^(j-1)][j-1]);

        //乘方是伪代码!

}

//solve

ans=max(f[l][k],f[r-2^k+1][k]);

所以就有两种情况:

①假如区间长度(r-l+1)正好是2k,那么就直接访问f[l][k];

②假如区间长度(r-l+1)是2k+p(p<2k),也就说明2k≤(r-l+1)<2k+1,我们可以慢慢地分治下去,利用前缀和,就形成了树状数组那样的东西,一段区间的最大值为 划分成两段区间最大值max1,max2相比取较大 ,但是这样太慢。

有一种更好的方法:其实我们可以用两个长度为2k的区间就一定能把这段[l,r]区间完美覆盖起来,会有重复,但是对求最大值这件事情没有影响,所以 这段区间的最大值=max(f[l][k],f[r-2k+1][k])。

限制:不能用来计算区间和,因为中间有重复部分,还有就是:不支持修改ST表!

2.树上倍增LCA(最近公共祖先):

一般是用线性Tarjan算法来求解(这个Tarjan算法和图论中求有向图强连通分量的Tarjan不同,都是一个人发明的),但是在ZHX十年的信息学奥赛生涯中没有用到这个算法,原因有俩:①没遇到这样的题目②不会!(笑哭脸),有兴趣可以了解一下。

下面介绍倍增的算法:

定义:f[i][j]表示:从树上编号为i的节点向上走2j步会走到哪个节点。

初始化:从j=0开始考虑,也就是从i号节点向上走1步到达的节点,就是i节点的父亲,所以:f[i][0]=father[i]。

转移:f[i][j]=f[f[i][j-1]][j-1],表示:从i节点往上走2j-1步后,再往上走2j-1步到达的点,等价于向上走2j步,因为2j-1+2j-1=2j。(j的范围大概[20,30)≈nlogn,只要保证2j>节点数目n即可)

现在我们构造出来这个f数组,下面介绍如何求两个点的LCA:

定义数组depth[i]表示i这个节点的深度,有以下两种情况:

①depth[p1]==depth[p2],具有一个重要的性质:两个节点同时向上走同样地步数,深度仍然相等,也就是说,我们让p1,p2一步一步地往上走,当走到同一个点时候,这个点一定是LCA!

for(int x=19;x>=0;x--) 

{

    if(f[p1][x]!=f[p2][x])//如果没有走到同一个点,继续往上走 

    {

        p1=f[p1][x];//p1往上跳 

        p2=f[p2][x];//p2往上跳 

    }     

}    

if(p1!=p2)//为什么要加这个判断?有可能p1=p2么?是有可能的!这个判断是防止一开始跳之前p1=p2这种情况 

{

    p1=f[p1][0];//因为上面的循环p1,p2只是走到了LCA的下方,这个判断只是处理最后一步:把p1或p2往上跳到它的父亲,就是LCA,返回即可 

return p1;//p1为LCA,返回

 

②depth[p1]!=depth[p2],假如p1比较深,就让p1往上跳到和p2深度一样的地方。

利用倍增f数组p1往上跳的方法:定义往上走步数step=depth[p1]-depth[p2],再利用二进制转换!

举个栗子:假如step=13,转为二进制=1101,可以得出13=8+4+1,:先走8步,再走4步,再走1步就好了。

int get_lca(int p1,int p2)

{

    if(dpeth[p1]<depth[p2]) swap(p1,p2);

    for(int x=19;x>=0;x--)

    {

    if((2^x)<=depth[p1]-depth[p2]) p1=f[p1][x];

    }

}

 

下面是另一种写法思路就不多讲

int x=0;

while (p1!=p2)

{

    if(!x||f[p1][x]!=f[p2][x]) 

    {

        p1=f[p1][x];

        p2=f[p2][x];

        x++;        

    }

    else x--;

}

 

3.快速幂:

按照一般思路,我们要计算ax的话,要写一个for循环,计算a×a×a×a…这样太™麻烦并且浪费时间!

这里运用倍增来实现快速幂,这也是运用到了分治的思想。

我们要求出x(x=2×k)个a的乘积,就可以分解为x/2个a的乘积的平方,这样就省去一半计算量,如果x是奇数,就在原先的基础上×a就可以了。

int ksm(int a,int x)//求a^x的快速幂 时间复杂度:O(logx) 

{

    int ans=1;

    while(x)

    {

        if(x&1) ans=(ans*a);//位运算:x&1==1则x为奇数

        a=a*a;

        x=x>>1;//位运算:右移一位,即将X除以2

    }

    return ans;

}

 

二、分治算法:

定义:将一个规模为N的问题分解为K个规模较小的子问题,这些子问题相互独立且与原问题性质相同。求出子问题的解,就可得到原问题的解。

这个算法的三个应用:

1.二分查找:

定义:给定排序数组,查询某个数是否在数组中

算法描述:在查找所要查找的元素时,首先与序列中间的元素进行比较,如果大于这个元素,就在当前序列的后半部分继续查找,如果小于这个元素,就在当前序列的前半部分继续查找,直到找到相同的元素,或者所查找的序列范围为空为止。

bool find(int x)//二分查找x是否在序列z[]中 

{

    left=0,right=n;

    while(left+1!=right)

    {

        middle=(left+right)>>1;

        if(z[middle]>=x) right=middle;

        else left=middle;

    }

}

 

还可以用lower_bound和upper_bound函数进行优化,用法详见下:

#include <iostream>

#include <algorithm>//必须包含的头文件,C++特有的库函数 

using namespace std;

int main()

{

    int point[5]={1,3,7,7,9};

    int ans;

    /*两个函数传入的:(数组名,数组名+数组长度,要查找的数字),返回的是一个地址,减去数组名即可得到数字在数组中的下标*/

    ans=upper_bound(point,point+5,7)-point;//按从小到大,7最多能插入数组point的哪个位置

    printf("%d ",ans);//输出数字在数组中的下标 

    ans=lower_bound(point,point+5,7)-point;按从小到大,7最少能插入数组point的哪个位置

    printf("%d\n",ans);//输出数字在数组中的下标 

    return 0;

}

/*

output:

4 2 

*/

 

2.归并排序(nlogn):

是分治法的典型应用。

归并过程:

比较a[i]和b[j]的大小,若a[i]≤b[j],则将第一个有序表中的元素a[i]复制到r[k]中,并令i和k分别加上1;

否则,将第二个有序表中的元素b[j]复制到r[k]中,并令j和k分别加上1。

如此循环下去,直到其中一个有序表取完,然后再将另一个有序表中剩余的元素复制到r中从下标k到下标t的单元

归并排序的算法我们通常用递归实现,先把待排序区间[s,t]以中点二分,接着把左边子区间排序,再把右边子区间排序,最后把左区间和右区间用一次归并操作合并成有序的区间[s,t]。

3.快速排序(nlogn):

一般在使用时候直接调用快排函数。

sort(快速排序,是C#特有的,不会退化为n2,比下面三个都要快,一般使用这个)

qsort(最坏情况下为n2,最好是n,期望为nlogn)

merge_sort(归并排序,稳定为nlongn)

heap_sort(堆排序,稳定为nlongn)

 

转载于:https://www.cnblogs.com/qbxt/p/10984714.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/275014.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用 CSS 用户选择控制选择

IE10 平台预览 4 包括一个新的 CSS 属性的支持-ms-user-select&#xff0c;这使得 Web 开发者控制完全可以选择什么的文本&#xff0c;在其网站上更容易。如果你是看我一整天都在我的工作站&#xff0c;您会注意到我读计算机上时&#xff0c;我选择的文本。我不是只有一个人读起…

一个在校的普通前端小姐姐的2021

大家好&#xff0c;我是若川。这是我的源码共读群里一个大三的前端小姐姐&#xff08;小曹同学&#xff09;的年度总结。她写了5篇源码笔记。同时做了很多项目&#xff0c;获得了很多奖。而且策划和建立了学校工作室的前端训练营&#xff0c;40人报名参加。总之就是现在的大学生…

按钮 交互_SwiftUI中的微交互—菜单按钮动画

按钮 交互Microinteractions have become increasingly important in a world with a dizzying number of digital platforms and an ocean of content. While microinteractions used to be considered an interesting resource in the early days of digital design, in toda…

JavaScript逻辑运算符的使用技巧

前言 !, &&, || 三个运算符是JavaScript中重要的逻辑运算符&#xff0c;本文将介绍这三个运算符在JavaScript实际编程中的有趣使用技巧。 取反运算符&#xff08;!&#xff09; 如果对一个值连续做两次取反运算&#xff0c;等于将其转为对应的布尔值&#xff0c;与Bool…

如何接触到最新的前端动态、最前沿的前端技术

众所周知&#xff0c;关注公众号可以了解学习掌握技术方向&#xff0c;学习优质好文&#xff0c;落实到自己项目中。还可以结交圈内好友&#xff0c;让自己融入到积极上进的技术氛围&#xff0c;促进自己的技术提升。话不多说&#xff0c;推荐这些优质前端公众号前端有道社区活…

选择控件— UI组件系列

重点 (Top highlight)The word “toggle” is a reference to a switch with a short handle that alternates between two states each time it is activated. You encounter it every time you “switch” on the lights.单词“ toggle”是指带有短手柄的开关&#xff0c;该开…

linux -- Linux diff与patch的深入分析

diff的输出格式分为传统格式和统一格式 1)diff的传统格式输出. ############################################ cat before.txt 输出: This is a line to be deleted This is a line that will be changed This is a line that will be unchanged cat after.txt 输出: This is …

shell命令之---sed

1. sed编辑器基础 1.1 替换标记 命令格式&#xff1a;s/pattern/replacement/flags $ cat data4.txt    This is a test of the test script.    This is the second test of the test script.    有4种可用的替换标记&#xff1a; 数字&#xff0c;表明新文本将替…

SEE Conf: Umi 4 设计思路文字稿

大家好&#xff0c;我是若川。持续组织了5个月源码共读活动&#xff0c;感兴趣的可以点此加我微信 ruochuan12 参与&#xff0c;每周大家一起学习200行左右的源码&#xff0c;共同进步。同时极力推荐订阅我写的《学习源码整体架构系列》 包含20余篇源码文章。复制此链接 https:…

用户体验改善案例_改善用户体验研究的5种习惯

用户体验改善案例There’s plenty of misunderstanding around user research, whether it’s the concept of validation or one-off anecdotes being thrown around as concrete evidence for a product decision.用户研究存在很多误解&#xff0c;无论是验证的概念还是一次性…

一场赛跑引起的并发知识

享学特邀作者&#xff1a;老顾前言我们小伙伴们是不是经常需要测试代码的性能&#xff1f;小伙伴们是不是就会想到jmeter进行压力测试一下&#xff0c;模拟N个用户同时执行下&#xff0c;看看响应的时间多少。今天老顾就用一个经典的比赛案例&#xff0c;来尝试自行编写个比赛业…

oracle中使用子查询为何取到大于自然数1 rownum 浅度解析

Oracle 没有提供TOP N 语句&#xff0c;若希望按特定条件查询前N 条记录&#xff0c;可以使用伪列ROWNUM。 ROWNUM 是对结果集加的一个伪列&#xff0c;即先查到结果集之后再加上去的一个列(注意&#xff1a;先要 有结果集)。 rownum 的值是oracle 顺序分配的从查询返回的行的编…

巴克莱对冲_“巴克莱的财政预算案”:使金钱管理对心理健康有效—用户体验案例研究

巴克莱对冲Disclaimer: all official Barclays assets used for this project are purely for educational/project purposes only and do not reflect the intentions of Barclays or any of its affiliates.免责声明&#xff1a;用于此项目的所有官方巴克莱资产纯粹是出于教育…

6 个对所有 Web 开发者都有用的 GitHub 仓库

作者&#xff1a;Mehdi Aoussiad原文&#xff1a;https://javascript.plainenglish.io/6-useful-github-repositories-for-all-web-developers-44f26912fd66大家好&#xff0c;我是若川。持续组织了5个月源码共读活动&#xff0c;感兴趣的可以点此加我微信 ruochuan12 参与&…

快速删除数据库中所有表中的数据

今天又学到一招&#xff0c;可以快速删除数据库中所有的用户表中的数据。我是个菜鸟&#xff0c;望各位大神多多指教 select truncate table Name ; from sysobjects where xtypeU order by name asc; 该条语句执行之后会将数据库中所有的表都查询出来&#xff0c;复制出来之…

openfiler的iSCSI配置(二)

为什么80%的码农都做不了架构师&#xff1f;>>> 一.openfiler iSCSI配置 1.启动iSCSI target server服务。在Services列表下。 2.设置访问列表。在System---Network Access Configuration下设置。 3.创建卷设备 二.ISCSI客户端配置 1.安装open-iscsi # apt-get ins…

送你一份用Electron开发桌面应用的避坑指南【送3本书,含犀牛书】

大家好&#xff0c;我是若川。持续组织了5个月源码共读活动&#xff0c;感兴趣的可以点此加我微信 ruochuan12 参与&#xff0c;新年第一次送3本书。抽奖规则见文末。如今&#xff0c;Electron 领域发生了重大的变革&#xff0c;Electron 版本更新换代极快&#xff0c;难以计数…

时间续

mois : janvier fvrier mars avril mai juin juillet aot septembre octobre novembre dcembre semaine : lundi mardi mercredi jeudi vendredi samedi dimanche 转载于:https://www.cnblogs.com/lavieenrose/archive/2012/02/18/2357597.html

nginx修改upstream不重启的方法(ngx_http_dyups_module模块)

为什么80%的码农都做不了架构师&#xff1f;>>> nginx很强大&#xff0c;第三方模块也不少,淘宝在nginx上很活跃&#xff0c;特别是章亦春&#xff0c;他参与的模块至少10&#xff0c; 好了今天主角不是他&#xff0c;是一款动态配置upstream的模块&#xff0c;这个…

c# 设计原则需要学习吗_向最好的学习:产品设计原则

c# 设计原则需要学习吗重点 (Top highlight)In my job as Design Team Lead at SimpleSite, I’ve recently been part of creating a set of Product Design Principles. In this process, I spent a lot of time studying the theory, learning about best practices, and ge…