CSP-S 2019 初赛知识点整理
Setsugesuka
·
2019-10-14 18:17:24
·
个人记录
这是我整理给自己的一份笔记,只是写博客上比较方便就写在上面,不知道为什么大家都看的到。。里面记的都是我自己没记住和我自己觉得很重要的,是 完 全 不 全 的。所以我这份东西只能参考,准备初赛还是需要自己啃初赛一本通,刷历年真题。
计算机基础知识常识
计算机常识
代别
年代
逻辑(电子)元件
第一代
1946-1958
电子管
第二代
1959-1964
晶体管
第三代
1965-1970
集成电路
第四代
1971- 至今
大规模、超大规模集成电路
1946$ 年 $2$ 月 美国 宾夕法尼亚大学 $ENIAC
冯诺依曼理论
计算机硬件设备由存储器、运算器、控制器、输入设备、输出设备五部分组成
储存程序思想
第一台采用二进制的冯诺依曼结构计算机 EDVAC ,由冯诺依曼设计。
巴贝奇设计了巴贝奇差分机和巴贝奇分析机,是数学分析机器。
工作站是微型机
计算机辅助设计($CAD$)、计算机辅助制造($CAM$)、计算机辅助教学($CAI$)、计算机辅助测试($CAT$)
第一个写程序的人 $Ada Lovelace
图灵 英国人 计算机科学理论基础第一人
摩尔定律 英特尔创始者之一戈登摩尔提出 计算机性能将以每两年翻一番的速度向前发展。
计算机硬件
计算机硬件设备由存储器、运算器、控制器、输入设备、输出设备五部分组成
CPU由运算器、控制器和一些寄存器组成
运算器 算术运算和逻辑运算
控制器 是计算机的指挥系统
CPU主要性能指标 主频和字长
存储器分为主存储器(内存储器)和辅助存储器(外存储器)
1B=8Bit$ $1KB=1024B$ $1MB=1024KB$ $1GB=1024MB$ $1TB=1024GB$ $1PB=1024TB
内存储器分为 RAM 、ROM 、Cache 三种
$ROM$ 只能读出 不能写入和修改 断电不会消失 主要用于检查计算机系统配置和提供最基本的输入/输出($I/O$)控制程序
$Cache$ 加快速度 外存->$RAM$->$Cache$->$CPU
常见的外存储器 软盘、硬盘、闪存、光盘
总线和分为数据总线(DB )、地址总线(AB )、控制总线(CB )
数据总线 双向 连接了CPU与各个部件 具体的传送方向由CPU控制
地址总线 传送地址信息 通常是单向的 20 条地址总线控制1MB
控制总线 传送控制信号 协调各部件操作
常用性能指标
字长 指一台计算机呢个处理的二进制码的位数 越长功能越强
运算速度 每秒钟所能执行的指令条数 单位是MIPS
主频 CPU 的时钟频率 单位有MHz (兆赫)与GHz (吉赫)
内存容量 内存储器能储存信息的总字节数 反应内存储器存储数据的能力
微机内的存储器地址是以字长编址的
微型计算机中 寄存器的存取速度最快 (不是高速缓存,因为寄存器在CPU里面)
打印机分类
针式打印机 通过打印头的 24 根针击打复印纸形成字体
喷墨打印机 通过加热喷嘴,使墨水产生气泡,喷到打印介质上
激光打印机 利用高压静电将感光鼓表面的“墨粉图像”转印到普通纸上
笔试绘图机 装有画笔的平板式绘图机
喷墨绘图仪 用于输出排料图和头版的专用宽幅单色绘图仪 打印介质是墨盒
### 中央处理器CPU
$CPU$ 是微机的核心部件,是决定微机性能的关键部件
$CPU$ 分为控制单元、逻辑单元、存储单元三个部分 由上万个晶体管组成
主要性能指标 时钟主频、字长、高速缓存容量、指令集合、动态处理技术、制造工艺、封装方式和工作电压等
$1971$ 年 英特尔公司 世界上第一款微处理器 $Intel$ $4004$ 字长 $4$ 位 是 $4$ 位微处理器
$1978$ 年 英特尔公司 $Intel$ $8086$ 第一个 $16$ 位微处理器
$1985$ 年 英特尔公司 $Intel$ $80386$ $32$ 位字长
主流 $CPU$ 字长几乎都达到了 $64$ 位
$CPU$ $PII300$ $300$ 指 $CPU$ 的主时钟频率
$DDR$ $SDRAM$ 是双倍速率同步动态随机存储器 不是 $CPU
Intel$ $Itanium$、$AMD$ $Athlon64$、$AMD$ $Opeteron$、$IBM$ $Power5$ 是 $CPU
$ALU$ 是算术逻辑部分 是 $CPU$ 的组成部分
### 计算机软件系统
桌面操作系统
1. $Unix$ 和类 $Unix$ 操作系统 $Mac$ $OS$ $X$、$Linux$ 发行版($Debian$、$Ubuntu$、$Linux$ $Mint$、$openSUSE$、$Fedora$、$Mandrake$、$Red$ $Hat$、$Centos$)
2. 微软公司 $Windows$ 操作系统
服务器操作系统
1. $Unix$ 系列 $SUNSolaris$、$IBM-AIX$、$HP-UX$、$FreeBSD$、$OS$ $X$ $Server$ $[6]$ 等
2. $Linux$ 系列 $Red$ $Hat$ $Linux$、$CentOS$、$Debian$、$UbutuServer$ 等
3. $Windows$ 系列
应用软件分类
1. 文字处理软件
2. 电子制表软件
3. 计算机辅助设计软件
4. 图形软件
5. 教育软件
6. 电子游戏软件
指令是一组二进制代码,规定了由计算机执行的程序的一步操作
一条指令由操作码和操作数组成
操作码 规定指令要完成的操作
操作数 针对操作的对象 可以没有
程序是计算机为了执行某种操作任务而将一条条指令按照一定的顺序排列起来的指令集
$OS/2$ 是 $IBM$ 公司的操作系统 $Arch/Info$ 是服务程序 不是操作系统
数据库软件 $MySQL$、$SQL$ $Server$、$Oracle$、$Visual$ $FoxPro
计算机语言
编写计算机程序所使用的语言称为程序设计语言
程序设计语言通常分为 机器语言、汇编语言和高级语言
机器语言 二进制代码来编写计算机程序 又称二进制语言
汇编语言 用一些符号代替机器指令所产生的语言叫做汇编语言
高级语言 有两种“翻译”方式
编译方式 先将整个源程序都转成二进制代码,生成目标程序,然后把目标程序连接成可执行的程序,以完成源程序要处理的运算并得到结果。
解释方式 边扫描边解释,对源程序的语句解释一条、执行一条,不产生目标程序。
编译性语言 C 、C++ 、Pascal 、Object Pascal 、Delphi 、Fortran
解释性语言 ASP 、PHP 、Java 、JavaScript 、VBScript 、Perl 、Python 、Ruby 、MATLAB 等
面向对象语言
借鉴了 20 世纪 50 年代的人工智能语言 LISP 它引入了动态绑定的概念和交互式开发环境的思想
始于 20 世纪 60 年代的离散事件模拟语言 Simula67 ,引入了类的要领和继承 它是世界上第一个支持面向对象的计算机语言 而 Smalltalk 是第二个
成型于 20 世纪 70 年代的 Smalltalk
面向对象语言的发展方向
纯面向对象语言 Smalltalk 、EIFFEL 等
混合型面向对象语言 C++ 、Objective-C 等
$C$ 语言不支持面向对象的程序设计方法
### 信息编码表示
将各类信息转化成“$0$”和“$1$”表示的代码 这一过程称为编码
比特是计算机中标识信息的数据编码中的最小单位
字节是存储器系统的最小存取单位
$ASCII$ 码是一种 $7$ 位编码(八位二进制码),它存储必须占全一个字节,也即占用 $8$ 位,最高位恒为 $0
最高位为 1 的便是扩充 ASCII 码 所以基本 ASCII 码和扩充 ASCII 码可以表示 0 ~ 255
一级汉字和二级汉字按使用频度分
一级汉字按拼音排序 二级汉字按部首排序
区位码->国际码 区码和位码分别加上 32
点阵每一个点用一个 bit 存取 不管笔画繁简 每个汉字所占的字节数相等
内存中数据的存取是以字节为单位的
计算机安全知识
计算机病毒特性
隐蔽性
潜伏性
传播性
激发性
破坏性和危害性
易读性、安全性等都不是计算机病毒特性
大部分计算机病毒主要造成计算机软件和数据的损坏 只有少数会影响到硬件
原码 补码 反码
小数点的两种表示方式
定点表示法 小数点位置固定不变,不必用记号表示出来
浮点表示法 两部分 尾数和阶码 尾数表示有效数值 阶码表示小数点位置
### 计算机网络
计算机网络 指利用通信技术和设备,把分布在不同地理位置上的多台计算机连接起来
计算机网络是现代通信技术与计算机技术相结合的产物
协议是计算机收发数据的规则
$TCP/IP$ 用于网络的一组通信协议 包括 $IP$ 与 $TCP
网络的主要功能
资源共享
信息传输
分布处理
综合信息服务
网络的地理位置分类 局域网(LAN )、城域网(MAN )、广域网(WAN )
网络的拓扑结构分类 星形、总线形、环形、树形、网状形
$Internet$ 网络本身的拓扑只是一种虚拟拓扑结构,无固定形式
网络的交换技术分类 电路交换、报文交换、分组交换
网络标准化组织($ISO$)提出的开放式系统互联($OSI$)参考模型,将数据从一个站点到达另一个站点的工作按层分割成七个不同的任务。
$TCP/IP$ 模型与 $OSI$ 模型的对应 左侧 $OSI$ 右侧 $TCP/IP
$IP$ 地址由网络 $ID$ 和唯一的主机 $ID$ 组成
IP地址分为 $A$、$B$、$C$、$D$、$E$ 五类,$A$、$B$、$C$ 为常用类,都由网络 $ID$ 和主机 $ID$ 两个部分组成。网络 $ID$ 也称网络地址,标识大规律 $TCP/IP$ 网际网络内的单个网段,连接并共享访问同一网络的所有系统在其完整的 $IP$ 地址内都有一个公用的网络 $ID$ ,这个 $ID$ 也用于唯一地识别大规模的网际网络内部的每个网络;主机 $ID$ 也叫做主机地址,识别每个网络内部的 $TCP/IP$ 节点,每个设备的主机 $ID$ 唯一地识别所在网络内的单个系统。

A类 $1.0.0.1$~$126.255.255.254
B类 128.1.0.1 ~191.255.255.254
C类 192.0.0.1 ~223.255.255.254
主机 ID 所有域不能都为 0 或 255
部分保留的专用地址
$172.16.0.0$~$172.31.255.255$ $B$ 类
$192.168.0.0$~$192.168.255.255$ $C$ 类
$IP$ 地址是一个 $64$ 位二进制码
计算机网络的最大优点是资源共享
### 因特网概述
因特网 采用的网络协议是 $TCP/IP$ 协议 也就是传输控制协议和网络协议
$TCP$ 协议用于负责网上信息的正确传输
$IP$ 协议负责将信息从一处传输到另一处
$TCP/IP$ 协议组织信息传输的方式是一种 $4$ 层的协议方式
| 名称 | 用处 |
| -----------: | -----------: |
| 应用层 | $Telnet$、$FTP$ 和 $e-mail$ 等 |
| 传输层 | $TCP$ 和 $UDP$ |
| 网络层 | $IP$、$ICMP$ 和 $IGMP$ |
| 网络接口层 | 设备驱动程序及接口卡 |
因特网起源于 $20$ 世纪 $60$ 年代中期 $ARPA$ 资助的 $ARPANET$ 此后提出了 $TCP/IP$ 协议
我国于 $1994$ 年 $4$ 月正式接入因特网。
$20$ 世纪 $80$ 年代末、$90$ 年代初刚起步
$1989$ 年我国第一个公用分组交换网 $CNPAC$ 建成运行
我国已陆续建成与 $Internet$ 互联的四个全国范围的公用网络
1. 中国公用计算机互联网($CHINANET$)
2. 中国金桥信息网($CHINAGBN$)
3. 中国教育和科研计算机网($CERNET$)
4. 中国科学技术网($CSTNET$)
网址指 $IP$ 地址、域名地址和 $URL
域名是字符形式的 IP 地址,格式为 开头.主机名.主机类别.国家名(可以不要)
一个域名一般有 3 ~5 个子段 中间用“.”隔开
域名由域名系统(DNS )统一管理 DNS 是一个分布式数据库系统,由域名空间、域名服务器和地址转换请求程序三部分组成
顶级域名有三类
国家顶级域名 cn (中国)、us (美国)、uk (英国)
国际顶级域名 int
通用顶级域名 com 、net 、edu 、gov
每一级域名都由英文字母和数字组成,最长不超过计划 63 个字符,层次低的写在左边,层次高的在右边,之间用英文的点号分开,完整的域名不超过 255 个字符
域名的最左边指主机名,通常用主机提供的服务表示。如果主机名被忽略,默认为 WWW
$WWW$ 瑞士日内瓦欧洲粒子实验室最先开发 超文本技术 $HTML$ 编写 超文本中隐含指向其他超文本的链接被称为超链接
$E-mail$ 地址格式为 收件人邮箱名@邮箱所在主机域名
文本传输协议 $FTP$ 用于在计算机间传输文件,通常所说的 $FTP$ 是基于该协议的一种服务
远程登录 $Telnet$ 指通过 $Internet$ 与其他主机连接
$URL$ 是因特网上的资源地址 每个 $Web$ 页面都有一个唯一的地址
浏览器 用于获取因特网上的各种资源
电子邮件协议
1. 简单邮件传输协议 $SMTP
电子邮件扩展协议 MIME
POP$ 协议 $POP
目前使用较普遍的 POP 协议为第三版 所以称之为 POP3
调制解调器 $modem$ 是硬件 能把计算机的数字信号翻译成可沿普通电话线传送的脉冲信号 脉冲信号被线路另一端的另一个调制解调器接收 译成计算机可懂的语言
路由器 连接因特网中各局域网、广域网的设备
计算机与外界局域网的连接通过主机箱内插入有线或无线网卡
网关 又称网间连接器、协议转换器 在网络层以上实现网络互连 是最复杂的网络互连设备 仅用于两个高层协议的不同网络互连
网桥 是早期的二端口二层网络设备 用来连接不同段 网桥的两个端口分别有一条独立的交换信道 不是共享一条背板总线 可隔离冲突域
$SMTP$ 是邮件协议 $POP3$ 是收邮件协议 $IMAP$ 是邮件访问协议
### 算法基础常识
算法的特征
1. 有穷性 每个步骤都能在有限的时间内完成
2. 确定性 每一步都必须有明确的定义
3. 输入 可以有 $0$ 个或多个输入
4. 输出 必须有一个或多个输出
5. 可行性
设数列有 $n$ 行 $m$ 列,可以总结出公式: $A[i][j]$ 的起始地址 $=SA+((i-1)×m+(j-1))×$单格字节数
| 名称 | 方法 | 时间复杂度 | 有序时 | 无序时 | 稳定性 |
| :----------- | :----------- | :----------- | :----------- | :----------- | :----------- |
| 冒泡排序 | 每次从前往后依次比较相邻两数, 把大的元素交换到后面,直到倒数第二个元素为次大,和水中的气泡浮起来一样 | $O(n^2)$ | $O(n)$ | $O(n^2)$ | 稳定 |
| 选择排序 | 从小到大每次找到第 $k$ 大的元素放到第 $k$ 个位置,直到把最大的元素放在末尾 | $O(n^2)$ | $O(n^2)$ | $O(n^2)$ | 不稳定 |
| 快速排序 | 每次选定一基准元素,把比它小的放左边,其他放右边,递归处理左右两边 | $O(nlogn)$ | $O(n^2)$ | $O(nlogn)$ | 不稳定 |
| 插入排序 | 从前往后,依次将还没排序的元素插入到前面已经排好的元素里面 | $O(n^2)$ | $O(n)$ | $O(n^2)$ | 稳定 |
| 希尔排序 | 按下标间隔给数列分组,对每组分别进行插入排序,然后减半下标间隔重新分组再排序,直到数列排好序 | $O(n^\frac {3}{2})$ | $O(n)$ | $O(n^\frac {3}{2})$ | 不稳定 |
| 桶排序 | 申请一个数组记录每个元素是否出现,读入元素后遍历这个数组,依次输出每个出现的元素 | $O(n)$ | $O(n)$ | $O(n)$ | 稳定 |
| 基数排序 | 桶的大小固定为 $10$ ,每次找出待排序元素中最大的值,按这个数的低位到高位对每个数进行桶排序,在时间复杂度中,我们认为 $r$ 是所采取的基数, $m$ 是堆数 | $O(nlog(r)m)$ | $O(nlog(r)m)$ | $O(nlog(r)m)$ | 稳定 |
| 归并排序 | 选中排序区域内的中点,递归左右两端,递归回去时将排序好的数组返回到上层,直到元素有序 | $O(nlogn)$ | $O(nlogn)$ | $O(nlogn)$ | 稳定 |
| 堆排序 | 按待排序序列构造成一个堆,依次把最大元素与待排序的最后一个元素交换,直到全部交换完 | $O(nlogn)$ | $O(nlogn)$ | $O(nlogn)$ | 不稳定 |
当待排序的数据已经为有序时,花费时间最多的是快速排序。
选择排序关键字的比较次数与初始排列顺序无关
基数排序不是以比较为主要操作的算法
逻辑运算符号
1. 非 $!
与 &&,∧
或 ||,∨
异或 ^
优先级 括号 > 非 > 与 > 或、异或 (两者同级)
与运算比或运算优先级高
集合运算的一元操作符优先 也就是补的优先级比交和并都高
出栈顺序在前的入栈顺序一定在后
队尾指针指向实际队尾元素所在的位置,队列为空时 head=tail
循环队列的元素个数为 (tail-head+n) mod n
k$ 叉树 设度为 $k$ 的节点有 $nk$ 个 叶节点数为 $n0$ 个,恒有 $n0=(k-1)nk+1
与某个点相连的边的个数是奇数个的点叫做奇点
存在欧拉路的条件 连通图 奇点数为 2
存在欧拉回路的条件 连通图 奇点数为 0
选择题常用知识
姚期智是首位华裔图灵奖得主
$Flickr$ 是典型的 $web2.0$ 应用
面向对象编程语言不采用自顶向下的设计方法进行设计
$BIOS$ 中包含的是各驱动的中断程序,而不是各驱动
$CPU$ 最早不是由英特尔公司发明的
基于比较的排序时间复杂度下限是 $O(nlogn)
空间复杂度的空间是指程序运行时理论上所占的内存空间
矢量图用点、直线或者多边形等基于数学方程的几何图元来表示图像
蓝牙和 $Wi-Fi$ 都是无线局域网设备
搜索引擎
1. $A$ 空格 $B$ 返回 $A$ 的结果和 $B$ 的结果的和并集
2. $"A"$ 返回所有一定包含 $A$ 的内容
中断指当出现需要时,$CPU$ 暂停当前程序的执行转而执行处理新情况的过程
$P2P$ 是点对点网络借款
$RMVB$ 也是视频格式
计算时间复杂度——主定理 [在洛谷日报上有详细的解释](https://www.luogu.org/blog/Chanis/master)
需要注意的是,$case1$ 与 $case3$ 应当是多项式大于,上文中并没有详细的写清楚。也就是说,对 $T(n)=3T(\frac{n}{4})+nlogn$,$nlogn$ 多项式大于 $n^{log_4 3}$,时间复杂度由后者主导,$O(T(n))=nlogn
一家四口人 至少两个人属于同一月份的概率是 $\frac {41}{96}
因为四个人都不在一个月的概率是 \frac {(12×11×10×9)}{12^4}=\frac{96}{55}
所以至少两个人在一个月的概率就是用 1 减去它等于 \frac {41}{96}
提供源节点和目的节点之间的信息传输服务的是网络层
一般的个人计算机在同一时刻只能存/取一个特定的内存单元
多任务操作系统不专用于多核心或多个 $CPU$ 架构的计算机系统
在操作系统的管理下,一个完整的程序在运行过程中可以被部分存放在内存中
分时系统让多个用户可以共享一台主机的运算能力,为保证每个用户都得到及时的相应通常会采用时间片轮转调度的策略
网络协议有很多层并不是因为新技术需要兼容过去老的方案
垂直于平面的直线所表示的向量为该平面的法向量
设 $A(x1,y1,z1),B(x2,y2,z2),C(x3,y3,z3)$是已知平面上的 $3$ 个点
$A,B,C$可以形成 $3$ 个向量,向量 $AB$,向量 $AC$ 和向量 $BC
设法向量坐标是 (x,y,z) 它与三个向量都垂直 点乘都为 0 ,可以解出法向量。
快排求第 k 大最优复杂度是 O(n) 的
汇编语言可以访问寄存器、内存单元、$I/O$ 接口
$WWW$ 不是网络协议
不在快速排序中引入随机化可能导致其排序时间退化为 $O(n^2)
$4G$ 制式标准 $TD-LTE$ 和 $FDD-LTE
4G$ 标准 $LTE-A$ 和 $WiMax
关于 $P$ 类、$NP$ 类、$NPC$ 类问题 [洛谷日报又有了](https://www.luogu.org/blog/styx-ferryman/chu-sai-bei-kao-gan-huo-p-wen-ti-np-wen-ti-npc-wen-ti-sha-sha-fen-fou)
克劳德·香农 $(Claude Shannon)$ 将热力学中的熵引入信息通信领域,标志着信息论研究的开端
$Unicode$ 是一种通用的字符编码,为世界上绝大部分语言设定了统一并且唯一的二进制编码,以满足跨语言、跨平台的文本转化。
$GB2312$ 最早一版的中文编码,每个字占据 $2bytes$。在 $GB2312$ 中收录了 $6763$ 个汉字以及 $682$ 个特殊符号,已经囊括了生活中最常用的所有汉字。它与 $ASCII$ 相互兼容
$Big5$ ,又称为大五码或五大码,是使用繁体中文(正体中文)社区中最常用的电脑汉字字符集标准,共收录 $13060$ 个汉字。
$TCP$ 协议属于传输层
蔡勒公式可以计算出某年某月某日是星期几,只适合于 $1582$ 年(中国明朝万历十年) $10$ 月 $15$ 日之后的情形。

其中 各字母的含义
1. $w$ 星期 $0-$星期日 $1-$星期一 依此类推
2. $c$ 世纪,年份前两位数
3. $y$ 年,年份后两位数
4. $m$ 月,$m \in [3,14]$ 也就是在公式中, $1$ 月要看作 $13$ 月, $2$ 月要看作 $14$ 月。
5. $d$ 日
6. $[]$ 表示下取整
天平称重用三分法
王选奖与计算机领域密切相关
对于一类 $f[n]=af[n-1]+bf[n-2]$ 的递推式,求第无穷大项趋近于多少,或者求某项的结果,我们一般都用特征根解出通项公式来做。
例题 $f[n]=(2002f[n-1]+2003f[n-2])$ $mod$ $2005$,$f[1]=1,f[0]=0$ 求第 $2005$ 项
原式等价于$f[n]=(-3f[n-1]-2f[n-2])$ $mod$ $2005
x^2+3x+2=0$ 解得 $x1=-1,x2=-2
A*(-1)^n+B*(-2)^n
代入第 0 项与第 1 项
A+B=0,-A-2B=1$ 解得 $A=1,B=-1
f[2005]=((-1)^{2005}+(-2)^{2005}*(-1))$ $mod$ $2005
f[2005]=(2^{2005}-1)$ $mod$ $2005
只要求 2^{2005} mod 2005
而 2005=401*5
2^{2005}$ $mod$ $401=32^{401}$ $mod$ $401
由费马小定理,上式等于 32
2^{2005}$ $mod$ $5=$ $2^{2005mod φ(5) + φ(5)}$ $mod$ $5
显然等于 32
因此 2^{2005} mod 401*5=32
f[2005]=31
图灵奖是由美国计算机协会 ACM 设立的
$C++$ 连接程序的功能是实现 $C++$ 的目标程序到可执行的 $EXE$ 文件的转换
结构化程序设计的基本方法是自顶向下,逐步求精。
操作系统是对计算机资源进行管理的系统软件
人们使用高级语言编写出来的程序,一般要先翻译成为目标程序
多维数组各维的下表范围可以由编程者根据需要自定义
$JPEG$ 是一种有损压缩的静态图像文件储存格式
快存速度大于主存 主存速度大于辅存
文件夹组织是一个有层次的树状结构,其中最顶层的是桌面
$CIH$ 是定期发作的病毒,可用设置 $FlashROM$ 写状态来避免病毒破坏 $ROM
数字音频采样和量化过程中所用的主要硬件是 模拟到数字的转换器(A/D 转换器)
数据结构是带有结构的数据元素的集合
汉字国际码 GB2312-80 一级汉字有 3755 个
在数据结构中,与所使用的计算机无关的数据叫逻辑结构
$ISP$ 指因特网服务提供商
在 $Windows$ 操作系统时,当硬盘空间不足时,一般情况下可最先考虑删除 $Temp$ 目录下的文件来释放空间
$WWW,FTP,SMTP$ 都属于应用层
在$Windows XP$ 中,$Alt+PrintScreen$ 可以把当前窗口作为一幅图像存入剪贴板中。
有符号单字节最小二进制数是 $10000000
剪贴板是内存中的一块区域
用户使用 ADSL 接入互联网时,双绞线的一端连接 ASDL Modem ,另一端连接到计算机的 网卡插口 。
计算机中汉字编码的最高位是 1 。
$BCD$ 码可以实现十进制数与二进制数之间的自动转换
$Windows$ 中的对话框可以移动,不能改变大小
$C++$ 程序在 $RAM$ 中运行
计算机系统由硬件系统和软件系统组成
计算机软件是由程序和文档组成
主要的调试方法包括 试探法 回溯法 演绎法 归纳法
信息加工 信息分类 信息存储 信息采集 都属于信息处理
没有安装操作系统和其他软件的计算机称为裸机
链表是采用链式存储结构的线性表
中国的第一枚高性能通用 $CPU$ 芯片是
集线器 网卡 中继器 都是局域网络设备
最接近机器指令的计算机语言是汇编语言
$NNTP$ 属于 $Internet$ 服务
办公室自动化 $OA$ 属于数据处理
$ISP$ 会提供上网账号、上网口令和域名服务器 $DNS$ 地址
数据一旦传送到目的节点,通过端口号机制可以将其传送给指定的应用程序
$Opera$ 是浏览器
$AOE$ 网中从源点到汇点最长的路径是关键路径,关键路径上的路径是关键活动
$3$ 柱汉诺塔通项公式为 $f(n)=2^n-1
4$ 柱汉诺塔的递推式为 $f(n)=min(2f(n-r)+2^r-1)
4$ 住汉诺塔的递推式可以化为 $f(n)=f(n-1)+2^{\lfloor \frac{\sqrt{8n-7}-1}{2}\rfloor}
$TCP$ 拥塞控制算法
1. 慢启动
2. 拥塞避免
3. 拥塞发生
4. 快速恢复
$DNS,RIP,TFTP$ 都是基于 $UDP$ 协议的
$RIP$ 路由信息协议
$TFTP$ 简单文件传输协议
$TELNET$ 是基于 $TCP$ 协议的
同时查找 $2n$ 个数中的最大值和最小值,最少比较次数为 $3n-2$ 次
前两个数比较,小的为最小值,大的为最大值。把剩下的 $2n-2$ 个数 分为 $n-1$ 组相邻的数,每组数里小的和最小值比较,大的和最大值比较,共 $3n-2$ 次
$karatsuba$ 大整数乘法算法的复杂度为 $O(n^{\log_2 3})
n$ 个不同节点构成的树的个数为 $n^{n-2}
路由器不属于局域网设备
插入排序是从已经排好序的后端开始往前找位置
------------
# 解决问题常用知识
------------
整除
1. $a \mid b $ 且 $a \mid c $,那么对 $\forall x,y \in Z$,恒有 $a \mid bx+cy
如果整数 x,y 满足 ax+by=1 ,且 a \mid n ,b \mid n ,那么 ab \mid n
若 b=qd+c 那么 d \mid b 的充要条件是 d \mid c
一个数末三位与末三位以前的数之差能被 7,11,13 整数,那么这个数能被 7,11,13 整除
同余
a$ $mod$ $p=x$,$a$ $mod$ $q=x$,$p,q$ 互质,那么 $a$ $mod$ $pq=x
公约数
gcd(x,y)*lcm(x,y)=x*y
卡特兰数
递归公式 f(n)=\sum_{i=0}^{n-1} f(i)×f(n-i-1)
递归公式 f(n)=\frac {f(n-1)×(4n-2)}{n+1}
组合公式 f(n)=\frac {C^n_{2n}}{n+1}
组合公式 f(n)=C^n_{2n}-C^{n-1}_{2n}
对 \prod_{i=0}^n ai 之间加任意括号,不同的运算顺序个数的答案是卡特兰数。
素数
若 p 为素数,那么 (p-1)! mod p=-1 它的逆定理也成立
若 p 为素数,a 为正整数,且 a,p 互质 则 a^{p-1} mod p=1
排列
从 n 个不同元素中选出 r 个数作排列,我们记作P(n,r)
P(n,r)=\frac{n!}{(n-r)!}$ 特别地 $P(n,n)=n!
从 n 个不同元素中可重复地选出 m 个元素 共 n^m 种
在 n 个元素中,有 n1,n2……nm 个元素彼此相同,且 \sum_{i=1}^m ni=n 则这 n 个元素的全排列个数有 \frac {n!}{\prod_{i=1}^n ai!} 种 这是全相异元素的全排列
在 n 个元素中,有 n1,n2……nm 个元素彼此相同,且 \sum_{i=1}^m ni=r 则从这 n 个元素中选出 r 个的排列有 \frac {P(n,r)}{\prod_{i=1}^n ai!} 种 这是不全相异元素的选排列
错排个数递推公式 f(1)=0,f(2)=1,f(n)=(n-1)(f(n-1)+f(n-2)) (n>=3)
从 n 个不同元素中选出 r 个元素,不分首尾地围成一个圈圈的排列方案数为 \frac{P(n,r)}{r}
组合
我们记 C(n,r) 为从 n 个元素里无序地选出 r 个元素的方案数
C(n,r)=\frac{n!}{r!×(n-r)!}
C(n,r)=C(n,n-r)
C(n,r)=C(n-1,r)+C(n-1,r-1)
\sum_{i=0}^n C(n,i) = 2^n
从 n 个不同元素中选出 r 个元素组成一个组合,且允许这 r 个元素重复使用,则称这样的组合为可重复组合,其组合数记作 H(n,r)
H(n,r)=C(n+r-1,r)
记 S(n,k) 是把 n 个元素划分到 k 个相同集合里,每个集合都不为空的方案数 有 S(n,1)=S(n,n)=1 且 S(n,k)=kS(n-1,k)+S(n-1,k-1)
最少任意交换次数为 n- 置换环的个数
最少相邻交换次数为逆序对数
```cpp
D[i][j]=min(min(D[i-1][j]+1,D[i][j-1]+1),(A[j-1]==B[i-1]?D[i-1][j-1]:D[i-1][j-1]+1));
```
二进制乘法和十进制乘法是等价的( $18$ 年初赛解决问题第二题)
平面图至多有 $3*n-6$ 条边 (画在平面上,所有边仅在顶点上才能相交的简单无向图)
一棵 $m$ 度树中有 $ni$ 个度数为 $i$ 的点,那么叶子节点的个数 $=\sum_{i=2}^n (i-1)ni+1
从 1 到 n 这 n 个数中选出若干个数,不能取相邻的数,至少取一个,方案数 f[n]=f[n-1]+f[n-2]+1
哈夫曼树的最小带权路径长度为\sum 叶节点权值× 叶节点到根的距离
阅读理解常用知识
新约瑟夫问题
可以证明 $m$ 一定是 $n,n+1...2n$ 的公倍数
我们一个一个枚举检验即可
快速找下一个排列的方法
1. 从尾端向前遍历,找到第一个位置 $i$ 满足 $val[i]<val[i+1]
从尾端向前遍历,找到第一个位置 j 满足 val[j]>val[i]
交换两个元素的位置,翻转 [i+1,n]
递归转递推
int solve(int n,int m)
{
if(m==1) return 1;
int sum=0;
for(int i=1;i<n;i++)
{
sum+=solve(i,m-1);
}
return sum;
}
solve(n,m)=\sum_{i=1}^n solve(i,m-1)
而 solve(n-1,m)=\sum_{i=1}^{n-1} solve(i,m-1)
所以 solve(n,m)=solve(n,m-1)+solve(n-1,m-1)
模型转换
小球从 (1,1) 开始 45° 角在 n×m 的矩阵内,遇到矩阵的边界则反弹,碰到死角停止,问小球最终会停止在哪里。
不难发现这个问题和我们从起点开始穿过一堆矩阵,第一次到达一个矩阵的右上角停下,是等价的。所以我们求出右上角的那个位置,然后对横纵坐标分别求小球经过了多少矩阵。以横坐标为例,假设横坐标是 x ,我们用 x 去除 n 如果是奇数,那最后的那个点横坐标为 n ,否则就为 1 。而这个右上角的点位置就是 (lcm(n,m),lcm(n,m)) 这也是很容易看出来的。
记 T 为一队列,初始时为空,现有 n 个总和不超过 32 的正整数依次入列。如果无论这些数具体为何值,都能找到一种出队的方式,使得存在某个时刻队列T中的数之和恰好为 9 ,那么 n 的最小值是
我们设队列里的元素为 a1,a2,a3...an ,这些元素的前缀和为 s1,s2,s3...sn 。那么原问题等价于,用 1 到 32 这些数构成 s 数组,问当 n 为多大时一定会出现 i<j i,j \in [1,n] 且 s[j]-s[i]=9 。不难想到用抽屉原理,以 (1,10),(2,11)... 为元素分组,只要有任意两个元素属于同一组时,就会有一种方案使得队列之和为 9 ,一共有 17 组,所以 n 的最小值是 18
条件反射猜用处
int work(int a,int b)
{
if(a%b)
return work(b,a%b);
return b
}
条件反射,一看就知道是求最大公约数
c[i][j]=c[i-1][j-1]+c[i-1][j];
求组合数
if(flag) cout<<"(";
for(int j=k;j<i;j++) cout<<b[j];
if(flag) cout<<")";
想到求除法,输出无限循环小数的循环节。
if(str[i]!=str[n-i-1]) flag=false
判断回文
for(int j=1;j<m;j++)
num=next(num);
cout<<num<<" ";
alive[num]=0;
if(i<n) num=next(num);
约瑟夫环
不会证的结论
f(i,j)$ 指 $i$ 和 $j$ 的二进制位不同的个数 有 $\sum_{i=1}^{2^n-1} \sum_{j=1}^{2^n-1} f(i,j)=n×2^{2n-1}
补充程序全算法
递归进阶
非递归枚举全排列
#include <bits/stdc++.h>
using namespace std;
const int MAXN=10;
int a[MAXN];
int n,tot;
inline void print()
{
for(int i=1;i<=n;i++)
cout<<" "<<a[i];
cout<<endl;
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++) a[i]=i;//初始化
print();//先输出最先的排列
tot=1;
for(int i=2;i<=n;i++) tot=tot*i;//计算一共有多少种排列
tot-=1;//删去已经生成的一个
for(int i=1;i<=tot;i++)
{
int j=n-1;
while(a[j]>=a[j+1]) j--;//找到第一个比右边大的数作为目标位置
int k=n;
while(a[k]<=a[j]) k--;//从后往前找到第一个比目标位置的数大的数
swap(a[j],a[k]);//交换两个数
reverse(a+j+1,a+n+1);//翻转目标位置后一格到最后这一段数组
print();
}
return 0;
}
快速排序
#include <bits/stdc++.h>
using namespace std;
const int MAXN=1e6+10;
int a[MAXN];
int n;
void qsort(int l,int r)
{
int mid=a[(l+r)>>1];//取中间的数作为基准值
int i=l,j=r;
while(i<=j)
{
while(a[i]<mid) i++;
while(a[j]>mid) j--;
if(i<=j)
{
swap(a[i],a[j]);//找到一对不符合的 交换
i++;
j--;
}
}
//如果没有交换就排完了
if(l<j) qsort(l,j);
if(i<r) qsort(i,r);
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i];
qsort(1,n);
for(int i=1;i<=n;i++)
cout<<a[i]<<" ";
return 0;
}
快速排序求第 k 大
#include <bits/stdc++.h>
using namespace std;
const int MAXN=1e4+10;
int a[MAXN];
bool vis[MAXN];
int n,k,ans=-1,cnt=0;
int solve(int l,int r,int k)
{
if(l==r) return l;
int tmp=rand()%(r-l)+l;
swap(a[tmp],a[l]);
int value=a[l];
int i=l,j=r;
while(i<j)
{
while(i<j&&a[j]<value) j--;
if(i<j){a[i]=a[j];i++;}else break;
while(i<j&&a[i]>value) i++;
if(i<j){a[j]=a[i];j--;}else break;
}
a[i]=value;
if(i<k) return solve(i+1,r,k);
if(i>k) return solve(l,i-1,k);
return i;
}
int main()
{
cin>>n>>k;
for(int i=1;i<=n;i++)
{
int sr;
cin>>sr;
if(!vis[sr])
a[++cnt]=sr,vis[sr]=1;
}
if(k>cnt)
{
puts("NO RESULT");
return 0;
}
ans=solve(1,cnt,cnt-k+1);
cout<<a[ans]<<endl;
return 0;
}
归并排序
#include <bits/stdc++.h>
using namespace std;
const int MAXN=1e6+10;
int a[MAXN],cc[MAXN];
int n;
void msort(int l,int r)
{
if(l==r)
return;
int mid=(l+r)>>1;
msort(l,mid);//递归处理左右两边
msort(mid+1,r);
int i=l,j=mid+1,k=l;
while(i<=mid&&j<=r)
{
if(a[i]<=a[j])
cc[k++]=a[i++];
else
cc[k++]=a[j++];
}
while(i<=mid)//处理还没排进去的
cc[k++]=a[i++];
while(j<=r)
cc[k++]=a[j++];
for(int i=l;i<=r;i++)//赋值给原数组
a[i]=cc[i];
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i];
msort(1,n);
for(int i=1;i<=n;i++)
cout<<a[i]<<" ";
return 0;
}
动态规划
```cpp
#include <bits/stdc++.h>
using namespace std;
const int MAXN=1e6+10;
int a[MAXN],dp[MAXN];//dp[i]表示以a[i]结尾的最长上升子序列的长度
int n,ans=0;
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i];
for(int i=1;i<=n;i++)
{
dp[i]=1;
for(int j=1;j<i;j++)
{
if(a[j]<a[i])
dp[i]=max(dp[i],dp[j]+1);
}
ans=max(ans,dp[i]);
}
cout<<ans<<endl;
}
```
$O(nlogn)$ 最长上升子序列
```cpp
#include <bits/stdc++.h>
using namespace std;
const int MAXN=1e6+10;
const int INF=0x3f3f3f3f;
int a[MAXN],dp[MAXN],low[MAXN];//low[i]表示长度为i的lis结尾元素的最小值
int n,ans=-1;
int main()
{
cin>>n;
memset(low,INF,sizeof(low));
for(int i=1;i<=n;i++)
cin>>a[i];
for(int i=1;i<=n;i++)
{
int j=lower_bound(low+1,low+1+n,a[i])-low;//找到可以接的位置里最优的那个
dp[i]=j;
ans=max(ans,dp[i]);
low[j]=a[i];
}
cout<<ans<<endl;
return 0;
}
```
$O(n^2)$ 最长公共子序列
```cpp
#include <bits/stdc++.h>
using namespace std;
const int MAXN=1010;
int dp[MAXN][MAXN];//dp[i][j]表示前一个序列考虑到了第i位后一个序列考虑到了第j位的最长公共子序列长度是多少
string a,b;
int n,m;
int main()
{
cin>>n>>m;
cin>>a>>b;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(a[i-1]==b[j-1])
dp[i][j]=max(dp[i][j],dp[i-1][j-1]+1);
else
dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
}
}
cout<<dp[n][m]<<endl;
return 0;
}
```
当序列是一个排列时 $O(nlogn)$ 最长公共子序列
```cpp
#include <bits/stdc++.h>
using namespace std;
const int MAXN=1e6+10;
const int INF=0x3f3f3f3f;
int a[MAXN],b[MAXN],dp[MAXN],low[MAXN],mp[MAXN];
int n,ans=0;
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i];
mp[a[i]]=i;
}
for(int i=1;i<=n;i++)
cin>>b[i];
for(int i=1;i<=n;i++)
{
if(mp[b[i]]>low[ans])
{
low[++ans]=mp[b[i]];
dp[i]=ans;
continue;
}
int j=lower_bound(low+1,low+ans+1,mp[b[i]])-low;
low[j]=mp[b[i]];
dp[i]=j;
}
cout<<ans<<endl;
return 0;
}
```
$O(n^3)$ 石子合并
```cpp
#include <bits/stdc++.h>
using namespace std;
const int MAXN=1010;
const int INF=0x3f3f3f3f;
int a[MAXN],sum[MAXN],dp[MAXN][MAXN];//dp[i][j] 第i堆石子到第j堆石子合并起来的最小代价
int n;
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i];
sum[0]=0;
for(int i=1;i<=n;i++)
sum[i]=sum[i-1]+a[i];
memset(dp,INF,sizeof(dp));
for(int i=1;i<=n;i++)
dp[i][i]=0;
for(int len=2;len<=n;len++)
{
for(int l=1;l<=n-len+1;l++)
{
int r=l+len-1;
for(int k=l;k<r;k++)
{
dp[l][r]=min(dp[l][r],dp[l][k]+dp[k+1][r]);
}
dp[l][r]+=sum[r]-sum[l-1];
}
}
cout<<dp[1][n]<<endl;
return 0;
}
```
$O(n^2)$ 石子合并 ($splay$ 维护可以到 $O(nlogn)$ )
每次找到第一个满足 $a[k]<=a[k+2]$ 的 $k$ 合并 $k,k+1$ 插入到第一个 $a[pos]>a[k]+a[k+1]$ 的 $pos$ 后面
```cpp
#include <bits/stdc++.h>
using namespace std;
vector<long long> a;
long long ans,sr;
int n;
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>sr;
a.push_back(sr);
}
for(int i=1;i<=n-1;i++)
{
int k=a.size()-2;
for(int j=0;j<a.size()-2;j++)
{
if(a[j]<=a[j+2])
{
k=j;
break;
}
}
long long sum=a[k]+a[k+1];
a.erase(a.begin()+k);
a.erase(a.begin()+k);
int pos=-1;
for(int j=k-1;j>=0;j--)
{
if(a[j]>sum)
{
pos=j;
break;
}
}
a.insert(a.begin()+pos+1,sum);
ans+=sum;
}
cout<<ans<<endl;
return 0;
}
```
$O(n^3)$ 金字塔
$dp[l][r]$ 表示 $a[l,r]$ 可以表示成多少种不同的子树,每次枚举 $[l,r]$ 的第一棵子树的位置 $k$ 运用加法原理统计总数量。
```cpp
#include <bits/stdc++.h>
using namespace std;
const int MAXN=310;
const long long MOD=1e9;
long long dp[MAXN][MAXN];
int a[MAXN];
int n;
long long dfs(int l,int r)
{
if(l>r) return 0;
if(a[l]!=a[r]) return 0;
if(l==r) return 1;
if(dp[l][r]!=-1) return dp[l][r];
dp[l][r]=0;
for(int k=l+2;k<=r;k++)
{
dp[l][r]=(dp[l][r]+dfs(l+1,k-1)*dfs(k,r)%MOD)%MOD;
}
return dp[l][r]%MOD;
}
int main()
{
string sr;
cin>>sr;
n=sr.size();
for(int i=1;i<=n;i++)
a[i]=sr[i-1]-'A';
memset(dp,-1,sizeof(dp));
cout<<dfs(1,n)<<endl;
}
```
$O(nmk)$ $01$ 背包第 $k$ 优解
```cpp
#include <bits/stdc++.h>
using namespace std;
const int MAXN=210;
int dp[5010][55],value[MAXN],cost[MAXN];
int n,v,k;
void solve()
{
int t1[55],t2[55],res1,res2,res;
memset(dp,0,sizeof(dp));
for(int i=1;i<=n;i++)
{
for(int j=v;j>=cost[i];j--)
{
for(int l=1;l<=k;l++)
{
t1[l]=dp[j-cost[i]][l]+value[i];
t2[l]=dp[j][l];
}
res1=res2=res=1;
t1[k+1]=t2[k+1]=-1;
while(res<=k&&(res1<=k||res2<=k))
{
if(t1[res1]>t2[res2])
dp[j][res]=t1[res1++];
else
dp[j][res]=t2[res2++];
if(dp[j][res-1]!=dp[j][res])
res++;
}
}
}
}
int t;
int main()
{
cin>>t;
while(t--)
{
cin>>n>>v>>k;
for(int i=1;i<=n;i++)
cin>>value[i];
for(int i=1;i<=n;i++)
cin>>cost[i];
solve();
cout<<dp[v][k]<<endl;
}
return 0;
}
```
$O(\sum_{i=1}^n \log_2 {ci}×m)$ 硬币 (二进制拆分)
```cpp
#include <bits/stdc++.h>
using namespace std;
const int MAXN=1e6+10;
int dp[MAXN],s[MAXN],a[MAXN],b[MAXN],cnt;
int n,m;
int main()
{
while((cin>>n>>m)&&n&&m)
{
memset(dp,0,sizeof(dp));
cnt=0;
for(int i=1;i<=n;i++)
cin>>a[i];
for(int i=1;i<=n;i++)
cin>>b[i];
for(int i=1;i<=n;i++)
{
int tot=0,tmp=1,cca=a[i];
while(tot+tmp<=b[i])//拆解元素
{
s[++cnt]=a[i];
tot+=tmp;
tmp<<=1;
a[i]<<=1;
}
b[i]-=tot;
if(b[i]) s[++cnt]=cca*b[i];
}
dp[0]=1;
for(int i=1;i<=cnt;i++)
{
for(int j=m;j>=s[i];j--)
{
dp[j]|=dp[j-s[i]];
}
}
int ans=0;
for(int i=1;i<=m;i++)
ans+=dp[i];
cout<<ans<<endl;
}
return 0;
}
```
### 哈希思想
$O(\frac{n^2}p)$ 雪花 (散列表+哈希函数)
```cpp
#include <bits/stdc++.h>
using namespace std;
const int MAXN=1e6+10;
const int MOD=99991;
int head[MAXN],nex[MAXN],cnt=0;
int snow[MAXN][6],n;
inline int H(int *a)
{
int sum=0,mul=1;
for(int i=0;i<6;i++)
{
sum=(sum+a[i])%MOD;
mul=(long long)mul*a[i]%MOD;
}
return (sum+mul)%MOD;
}
inline bool equal(int *a,int *b)
{
for(int i=0;i<6;i++)
{
for(int j=0;j<6;j++)
{
bool eq=true;
for(int k=0;k<6;k++)
{
if(a[(i+k)%6]!=b[(j+k)%6]) eq=false;
}
if(eq) return true;
eq=true;
for(int k=0;k<6;k++)
{
if(a[(i+k)%6]!=b[(j-k+6)%6]) eq=false;
}
if(eq) return true;
}
}
return false;
}
inline bool insert(int *a)
{
int val=H(a);
for(int i=head[val];i;i=nex[i])
{
if(equal(snow[i],a)) return true;
}
memcpy(snow[++cnt],a,6*sizeof(int));
nex[cnt]=head[val];
head[val]=cnt;
return false;
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
{
int a[8];
for(int j=0;j<6;j++)
cin>>a[j];
if(insert(a))
{
puts("Twin snowflakes found.");
return 0;
}
}
puts("No two snowflakes are alike.");
}
```
### 单调性
$O(n)$ 糟糕的一天 (单调栈)
动态维护有多少牛可以看见当前这头牛
```cpp
#include <bits/stdc++.h>
using namespace std;
const int MAXN=1e5+10;
int a[MAXN],n;
long long ans=0;
stack<int> s;
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i];
for(int i=1;i<=n;i++)
{
while(!s.empty()&&s.top()<=a[i])
s.pop();
ans+=s.size();
s.push(a[i]);
}
cout<<ans<<endl;
return 0;
}
```
$O(n)$ 滑动窗口 (单调队列)
当一个选手比你小又比你强,那你就可以退役了
```cpp
#include <bits/stdc++.h>
using namespace std;
const int MAXN=1e7+10;
struct node
{
int index,x;
};
int a[MAXN];
deque<node> q;
int n,m;
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
cin>>a[i];
for(int i=1;i<=n;i++)
{
if(q.empty())
puts("0");
else
{
if(q.front().index+m<i)
q.pop_front();
cout<<q.front().x<<endl;
}
while(!q.empty()&&q.back().x>=a[i])
q.pop_back();
q.push_back(node{i,a[i]});
}
return 0;
}
```
### 数论
$O(n)$ 线性筛
```cpp
#include <bits/stdc++.h>
using namespace std;
const int MAXN=1e7+10;
int prime[MAXN],p[MAXN],tot=0;
int n,m;
inline void init()
{
memset(p,0,sizeof(p));
memset(prime,0,sizeof(prime));
prime[1]=prime[0]=1;
for(int i=2;i<=n;i++)
{
if(!prime[i])
p[++tot]=i;
for(int j=1;j<=tot&&i*p[j]<=n;j++)
{
prime[i*p[j]]=1;
if(i%p[j]==0)
break;
}
}
}
int main()
{
cin>>n>>m;
init();
int sr;
while(m--)
{
cin>>sr;
if(!prime[sr])
puts("Yes");
else
puts("No");
}
}
```
### 最小生成树
$O(nlogn)$ 克鲁斯卡尔最小生成树
```cpp
#include <bits/stdc++.h>
using namespace std;
const int MAXN=1e7+10;
struct node
{
int u,v,w;
};
node edges[MAXN];
int fa[MAXN],ans=0;
int n,m;
inline bool cmp(node x,node y)
{
return x.w<y.w;
}
int find(int x)
{
if(x==fa[x]) return x;
else return fa[x]=find(fa[x]);
}
int main()
{
cin>>n>>m;
for(int i=1;i<=m;i++)
cin>>edges[i].u>>edges[i].v>>edges[i].w;
sort(edges+1,edges+1+m,cmp);
for(int i=1;i<=n;i++)
fa[i]=i;
for(int i=1;i<=m;i++)
{
int x=find(edges[i].u),y=find(edges[i].v);
if(x==y) continue;
fa[x]=y;
ans+=edges[i].w;
}
cout<<ans<<endl;
return 0;
}
```
$O(nlogn)$ 普里姆最小生成树
```cpp
#include <bits/stdc++.h>
using namespace std;
const int MAXN=5010;
int mp[MAXN][MAXN],dis[MAXN];
bool vis[MAXN];
int n,m,ans=0;
inline void prim()
{
memset(dis,0x3f3f3f3f,sizeof(dis));
memset(vis,false,sizeof(vis));
dis[1]=0;
for(int i=1;i<n;i++)
{
int x=0;
for(int j=1;j<=n;j++)
if(!vis[j]&&(x==0||dis[j]<dis[x])) x=j;
vis[x]=true;
for(int y=1;y<=n;y++)
if(!vis[y]) dis[y]=min(dis[y],mp[x][y]);
}
}
int main()
{
cin>>n>>m;
memset(mp,0x3f3f3f,sizeof(mp));
for(int i=1;i<=n;i++)
mp[i][i]=0;
for(int i=1;i<=m;i++)
{
int x,y,z;
cin>>x>>y>>z;
mp[x][y]=mp[y][x]=min(mp[x][y],z);
}
prim();
for(int i=2;i<=n;i++)
ans+=dis[i];
cout<<ans<<endl;
return 0;
}
```
$O(nlog^2n)$ 树剖严格次小生成树
```cpp
#include <bits/stdc++.h>
using namespace std;
template <class T>
inline bool read(T &ret)
{
char c;
int sgn;
if (c = getchar(), c == EOF)
{
return 0;
}
while (c != '-' && (c < '0' || c > '9'))
{
c = getchar();
}
sgn = (c == '-') ? -1 : 1;
ret = (c == '-') ? 0 : (c - '0');
while (c = getchar(), c >= '0' && c <= '9')
{
ret = ret * 10 + (c - '0');
}
ret *= sgn;
return 1;
}
template <class T>
inline void write(T x)
{
if (x > 9)
{
write(x / 10);
}
putchar(x % 10 + '0');
}
const int MAXN=1e6+10;
const int INF=0x3f3f3f3f;
struct edge
{
int u,v,w,nex;
};
struct node
{
int u,v,w;
bool used;
bool operator <(const node &o) const
{
return w<o.w;
}
};
struct trenode
{
long long ans1,ans2;
int l,r,ls,rs;
};
int krufa[MAXN];
edge e[MAXN<<1];
int head[MAXN],cnt=0;
int dep[MAXN],fa[MAXN],sz[MAXN],top[MAXN],val[MAXN],a[MAXN],id[MAXN],son[MAXN],rk[MAXN];
int tot=0,trecnt=0,root;
node nodes[MAXN];
trenode tre[MAXN];
int n,m;
long long ans;
int find(int x)
{
if(x==krufa[x]) return x;
else return krufa[x]=find(krufa[x]);
}
inline void add(int u,int v,int w)
{
e[++cnt].u=u;
e[cnt].v=v;
e[cnt].w=w;
e[cnt].nex=head[u];
head[u]=cnt;
}
inline void kru()
{
sort(nodes+1,nodes+1+m);
for(int i=1;i<=n;i++)
krufa[i]=i;
int cc=0;
for(int i=1;i<=m;i++)
{
int u=nodes[i].u,v=nodes[i].v;
int fu=find(u),fv=find(v);
if(fu!=fv)
{
add(u,v,nodes[i].w);
add(v,u,nodes[i].w);
krufa[fu]=fv;
ans+=nodes[i].w;
++cc;
nodes[i].used=true;
if(cc==n-1)
break;
}
}
}
void dfs1(int u)
{
sz[u]=1;
for(int i=head[u];i;i=e[i].nex)
{
int v=e[i].v;
if(v==fa[u])
continue;
fa[v]=u;
dep[v]=dep[u]+1;
a[v]=e[i].w;
dfs1(v);
sz[u]+=sz[v];
if(sz[v]>sz[son[u]])
son[u]=v;
}
}
void dfs2(int u,int tp)
{
top[u]=tp;
id[u]=++tot;
rk[tot]=u;
if(!son[u])
return;
dfs2(son[u],tp);
for(int i=head[u];i;i=e[i].nex)
{
int v=e[i].v;
if(v!=fa[u]&&v!=son[u]) dfs2(v,v);
}
}
inline void pushup(int x)
{
tre[x].ans1=max(tre[tre[x].ls].ans1,tre[tre[x].rs].ans1);
if(tre[tre[x].ls].ans1==tre[tre[x].rs].ans1)
tre[x].ans2=max(tre[tre[x].ls].ans2,tre[tre[x].rs].ans2);
else
tre[x].ans2=min(tre[tre[x].ls].ans1,tre[tre[x].rs].ans1);
}
void build(int l,int r,int x)
{
if(l==r)
{
tre[x].ans1=a[rk[l]];
tre[x].l=tre[x].r=l;
return;
}
int mid=(l+r)>>1;
tre[x].ls=++trecnt;
tre[x].rs=++trecnt;
build(l,mid,tre[x].ls);
build(mid+1,r,tre[x].rs);
tre[x].l=tre[tre[x].ls].l;
tre[x].r=tre[tre[x].rs].r;
pushup(x);
}
int query(int L,int R,int x,int key)
{
if(tre[x].l>R||tre[x].r<L)
return -INF;
if(L<=tre[x].l&&tre[x].r<=R)
{
if(key==tre[x].ans1)
return tre[x].ans2;
return tre[x].ans1;
}
int mid=(tre[x].l+tre[x].r)>>1,ret=-INF;
if(L<=mid)
ret=max(ret,query(L,R,tre[x].ls,key));
if(R>mid)
ret=max(ret,query(L,R,tre[x].rs,key));
return ret;
}
inline int sum(int x,int y,int key)
{
int ret=0;
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]]) swap(x,y);
ret=max(ret,query(id[top[x]],id[x],root,key));
x=fa[top[x]];
}
if(id[x]>id[y])
swap(x,y);
ret=max(ret,query(id[x]+1,id[y],root,key));
return ret;
}
int main()
{
read(n),read(m);
for(int i=1;i<=m;i++)
read(nodes[i].u),read(nodes[i].v),read(nodes[i].w);
kru();
dfs1(1);
dfs2(1,1);
build(1,n,root=++trecnt);
long long ret=1e18;
for(int i=1;i<=m;i++)
{
if(!nodes[i].used)
{
ret=min(ret,ans+nodes[i].w-sum(nodes[i].u,nodes[i].v,nodes[i].w));
}
}
write(ret);
return 0;
}
```
### 最短路径
$O(nlogn)$ 迪杰斯特拉
```cpp
#include <bits/stdc++.h>
using namespace std;
const int MAXN=1e7+10;
struct edge
{
int u,v,w,nex;
};
edge e[MAXN];
int head[MAXN],cnt=0;
int dis[MAXN];
bool vis[MAXN];
int n,m,s;
inline void add(int u,int v,int w)
{
e[++cnt].u=u;
e[cnt].v=v;
e[cnt].w=w;
e[cnt].nex=head[u];
head[u]=cnt;
}
inline void dijkstra(int st)
{
memset(dis,0x3f3f3f3f,sizeof(dis));
memset(vis,false,sizeof(vis));
dis[st]=0;
priority_queue<pair<int,int> >q;
q.push(make_pair(0,st));
while(!q.empty())
{
int u=q.top().second;
q.pop();
if(vis[u]) continue;
vis[u]=true;
for(int i=head[u];i;i=e[i].nex)
{
int v=e[i].v;
if(dis[v]>dis[u]+e[i].w)
{
dis[v]=dis[u]+e[i].w;
q.push(make_pair(-dis[v],v));
}
}
}
}
int main()
{
cin>>n>>m>>s;
for(int i=1;i<=m;i++)
{
int x,y,z;
cin>>x>>y>>z;
add(x,y,z);
}
dijkstra(s);
for(int i=1;i<=n;i++)
cout<<dis[i]<<" ";
return 0;
}
```
$O(n^3)$ 弗洛伊德
```cpp
for(int k=1;k<=n;k++)
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
mp[i][j]=min(mp[i][j],mp[i][k]+mp[k][j]);
}
}
}
```
$O(inf)$ 队列优化的贝尔曼福特
```cpp
#include <bits/stdc++.h>
using namespace std;
const int MAXN=1e7+10;
struct edge
{
int u,v,w,nex;
};
edge e[MAXN];
int head[MAXN],cnt=0;
int dis[MAXN],n,m,s;
bool vis[MAXN];
queue<int> q;
inline void add(int u,int v,int w)
{
e[++cnt].u=u;
e[cnt].v=v;
e[cnt].w=w;
e[cnt].nex=head[u];
head[u]=cnt;
}
void spfa(int st)
{
memset(dis,0x3f3f3f3f,sizeof(dis));
memset(vis,false,sizeof(vis));
dis[st]=0,vis[st]=1;
q.push(st);
while(!q.empty())
{
int u=q.front();
q.pop();
vis[u]=false;
for(int i=head[u];i;i=e[i].nex)
{
int v=e[i].v;
if(dis[v]>dis[u]+e[i].w)
{
dis[v]=dis[u]+e[i].w;
if(!vis[v]) q.push(v),vis[v]=true;
}
}
}
}
int main()
{
cin>>n>>m>>s;
for(int i=1;i<=m;i++)
{
int x,y,z;
cin>>x>>y>>z;
add(x,y,z);
}
spfa(s);
for(int i=1;i<=n;i++)
{
if(dis[i]==0x3f3f3f3f)
cout<<"2147483647"<<" ";
else
cout<<dis[i]<<" ";
}
return 0;
}
```
### 高精度计算
高精度加法
```cpp
#include <bits/stdc++.h>
using namespace std;
const int MAXN=1e5+10;
char a1[MAXN],b1[MAXN];
int a[MAXN],b[MAXN],c[MAXN];
int main()
{
scanf("%s",a1);
scanf("%s",b1);
if(a1[0]==48&&b1[0]==48)
{
puts("0");
return 0;
}
int lena=strlen(a1),lenb=strlen(b1);
for(int i=0;i<lena;i++)
a[lena-i-1]=int(a1[i]-48);
for(int i=0;i<lenb;i++)
b[lenb-i-1]=int(b1[i]-48);
int sz=max(lena,lenb);
for(int i=0;i<sz;i++)
{
c[i]+=a[i]+b[i];
c[i+1]+=c[i]/10;
c[i]%=10;
}
sz++;
while(c[sz]==0) sz--;
for(int i=sz;i>=0;i--)
cout<<c[i];
cout<<endl;
return 0;
}
```
高精度减法
```cpp
#include <bits/stdc++.h>
using namespace std;
const int MAXN=1e5+10;
string a1,b1;
int a[MAXN],b[MAXN],c[MAXN];
bool pd=false;
int main()
{
cin>>a1>>b1;
int lena=a1.size(),lenb=b1.size();
if(lena<lenb||(lena==lenb&&a1<b1))
{
swap(a1,b1),pd=true;
lena=a1.size();
lenb=b1.size();
}
for(int i=lena;i>0;i--) a[i]=a1[lena-i]-'0';
for(int i=lenb;i>0;i--) b[i]=b1[lenb-i]-'0';
int sz=max(lena,lenb);
for(int i=1;i<=sz;i++)
{
if(a[i]<b[i])
{
a[i+1]--;
a[i]+=10;
}
c[i]=a[i]-b[i];
}
while(c[sz]==0) sz--;
if(pd==true) cout<<"-";
for(int i=sz;i>0;i--)
cout<<c[i];
if(sz<1)
cout<<0;
return 0;
}
```
高精度乘法 (高精×单精)
```cpp
#include <bits/stdc++.h>
using namespace std;
const int MAXN=1e6+10;
char a1[MAXN];
int a[MAXN],b;
int ans[MAXN],sz=0;
int main() {
scanf("%s",a1);
scanf("%d",&b);
int lena=strlen(a1);
if(lena==1&&a1[0]=='0')
{
cout<<0<<endl;
return 0;
}
if(b==0)
{
cout<<0<<endl;
return 0;
}
for(int i=lena-1;i>-1;i--)
a[lena-1-i]=a1[i]-'0';
int c=0;
int temp=0;
for(int i=0;i<lena;i++)
{
temp=a[i]*b+c;
c=temp/10;
ans[sz++]=temp%10;
}
if(c!=0)
ans[sz++]=c;
for(int i=sz-1;i>-1;i--)
cout<<ans[i];
}
```
高精度乘法 (高精×高精)
```cpp
#include <bits/stdc++.h>
using namespace std;
const int MAXN=1e6+10;
char a1[MAXN],b1[MAXN];
int a[MAXN],b[MAXN],c[MAXN];
int main()
{
scanf("%s",a1);
scanf("%s",b1);
int lena=strlen(a1),lenb=strlen(b1);
for(int i=0;i<lena;i++)
a[lena-i-1]=a1[i]-'0';
for(int i=0;i<lenb;i++)
b[lenb-i-1]=b1[i]-'0';
for(int i=0;i<lena;i++)
{
int x=0;
for(int j=0;j<lenb;j++)
{
c[i+j]+=a[i]*b[j]+x;
x=c[i+j]/10;
c[i+j]%=10;
}
c[lenb+i]=x;
}
int lenc=lena+lenb;
while(c[lenc]==0&&lenc)
lenc--;
for(int i=lenc;i>=0;i--)
cout<<c[i];
return 0;
}
```
高精度除法 (高精/单精)
```cpp
#include <bits/stdc++.h>
using namespace std;
const int MAXN=1e6+10;
string s;
int q,rest,n;
int p[MAXN];
int main()
{
cin>>s>>q;
n=s.size();
for(int i=0;i<n;i++)
{
p[i]=s[i]-'0';
}
int i=1;
rest=p[0];
while(rest<q&&i<n)
{
rest=rest*10+p[i];
i++;
}
if(rest<q)
{
cout<<0<<endl;
}
else
{
cout<<rest/q;
while(i<n)
{
rest=rest%q*10+p[i];
i++;
cout<<rest/q;
}
cout<<endl;
}
cout<<rest%q<<endl;
return 0;
}
```
高精度除法 (高精/高精)
```cpp
#include <bits/stdc++.h>
using namespace std;
const int MAXN=1e6+10;
string a1,b1;
int a[MAXN],b[MAXN],c[MAXN],t[MAXN];
inline int compare(int aa[],int bb[])
{
if(aa[0]>bb[0]) return 1;
if(aa[0]<bb[0]) return -1;
for(int i=aa[0];i>0;i--)
{
if(aa[i]>bb[i]) return 1;
if(aa[i]<bb[i]) return -1;
}
return 0;
}
inline void numcpy(int aa[],int bb[],int l)
{
for(int i=1;i<=aa[0];i++) bb[i+l-1]=aa[i];
bb[0]=aa[0]+l-1;
}
int main()
{
cin>>a1>>b1;
a[0]=a1.size(),b[0]=b1.size(),c[0]=a[0]-b[0]+1;
for(int i=1;i<=a[0];i++) a[i]=a1[a[0]-i]-'0';
for(int i=1;i<=b[0];i++) b[i]=b1[b[0]-i]-'0';
for(int i=c[0];i>0;i--)
{
memset(t,0,sizeof(t));
numcpy(b,t,i);
while(compare(a,t)>=0)
{
c[i]++;
if(!compare(a,t))
{
a[0]=0;
continue;
}
for(int i=1;i<=a[0];i++)
{
if(a[i]<t[i]) a[i+1]--,a[i]+=10;
a[i]-=t[i];
}
while(a[0]>0&&!a[a[0]]) a[0]--;
}
}
while(c[0]>0&&!c[c[0]]) c[0]--;
if(!c[0]) cout<<0<<endl;
else for(int i=c[0];i>0;i--) cout<<c[i];
return 0;
}
```