【蒟蒻の笔记】CSP初赛复习笔记

CSP初赛复习笔记

初赛什么都能考?就nm离谱/doge

计算机科学发展史

起源

图灵和图灵机以及其他成就

Alan Mathison Turing——艾伦·麦席森·图灵,于1936年发表了图灵机这一理论模型,这一模型是对人类行为的一种模拟,同时也为后续的计算机科学奠定了基础。

图灵试验,又称图灵测试,即判断一个机器是否具有人类智能的一种标准,这一标准目前没有任何计算机可以通过。

图灵完备:在可计算性理论里,如果一系列操作数据的规则(如指令集、编程语言、细胞自动机)可以用来模拟(单带)图灵机那么这个系统是图灵完备的。

后来人们为了纪念伟大的计算机科学之父,人工智能之父,艾伦·麦席森·图灵,设立了图灵奖,这相当于信息学中的诺贝尔奖

冯·诺依曼结构

1944年,计算机之父,博弈论之父冯·诺依曼提出了冯诺伊曼理论,这项理论延续至今甚至非冯结构计算机成了科幻小说的常客

冯诺依曼结构指出了一种电脑通用的结构:
由输入设备读入数据,放入存储设备中,然后CPU(中央处理器)中的控制器控制CPU中的运算器进行操作,然后将结果按指令存入存储设备,最后输出设备按指令进行输出

热力学中的熵在信息通信领域

1948年,克劳德·香农将热力学中的熵引入了信息通信领域

摩尔定律

摩尔定律是因特尔创始人戈登·摩尔所提出的一个“不像是定律的”定律,他指出:成电路上可以容纳的晶体管数目在大约每经过18个月便会翻一番。

请注意,摩尔定律没有理论依据,不能成为严谨的定律,但他确实成为了现实(目前)。

世界上第一台通用计算机

世界上第一台通用计算机于1946年2月14日在宾夕法尼亚大学制造出,名字叫ENIAC,全称Electronic Numerical Integrator And Computer(电子数字积分计算机)

目前世界上公认的第一台计算机是阿塔纳索夫-贝瑞计算机,即Atanasoff–Berry Computer(ABC),不可编程,仅用来求线性方程组

计算机的分类

计算机逻辑(电子)原件分为:

电子管:1946-1958
晶体管:1959-1964
小型集成电路:1965-1970
大/超大型集成电路:1971往后

从具体的性能分析可分为:

巨型机
大型机
中型机
小型机
微型机

计算机结构

那我们来看一下伟人为我们留下的成果:计算机系统

计算机系统分为软件系统和硬件系统,没有软件的计算机是空壳子,而硬件是计算机的物理基础。

硬件系统

计算机硬件系统分为主机和外设,分别有几部分组成

主机

主机的主要构成是中央处理器(CPU)和内存

中央处理器(CPU)

CPU作为中央处理器,任务就是处理内存中的数据。
CPU由运算器,控制器和寄存器组成。

运算器:负责执行运算任务
控制器:计算机的指挥系统,合理调配计算机处理工作
寄存器:暂存指令、数据和地址

CPU的评判标准是主频和字长

主频

CPU的主频的单位一般是GHz,笔者的电脑CPU主频为2.60GHz

字长

字长指的是CPU每次可读取的位数,每次读取的内容称为字。
现在一般个人电脑的字长是64,曾经是更低的位数,有的大型机配备了128位字长的CPU
1971年,Intel生产了第一个四位字长的CPU——4004
随后,德州仪器的TMX 1795被制造出来,但没有张扬,鲜为人知
1971年,Intel生产了第一个16位字长的CPU——8086
1971年,Intel生产了第一个32位字长的CPU——80386
1971年,Intel生产了第一个64位字长的CPU——Pentium
AMD你干啥去了不搞科研吗

内存

内存分为ROM,RAM,Cache(不是CSGO里面那个反CT叉车)

ROM(只读存储器)

ROM中的内容是在制作存储器的是时候就写入的,里面的内容无法被更改(物理上),其中的信息在断电时也不会丢失,ROM中的信息是用来检查计算机的配置情况以及提供最基本的输入输出控制程序。

RAM(随机存储器,读写存储器)

RAM的内容可以随时写入和读出,非常常用,但是断电后RAM中的所有信息将会丢失。
一般RAM从外存读入数据,在经由Cache交给CPU处理
*随机存储器中的内容并非随机存放,不过相对于其他存储器来说……

Cache(高速缓冲存储器,不是CSGO的叉车)

随着时代的发展,CPU的效率不断提高,RAM的速度无法跟上CPU,这导致了CPU的性能出现冗余,于是在CPU和RAM之间出现了Cache,即高速缓冲存储器。

外设

外设可以分为三大类:输入设备,输出设备和外部存储设备。

输入设备

输入设备指的是从外界的操作中得到信息并传输给计算机,包括但不限于键盘,鼠标,麦克风,扫描仪。

输出设备

输出设备是指根据指令进行输出操作的设备,包括但不限于显示屏,打印机,音响。

外部存储设备

外部存储设备是存储信息的载体,包括但不限于硬盘,光盘,U盘。

某些不被定义的东西

显卡是辅助CPU进行图形运算等操作的,可以直接辅助显示器以达到更好的图形渲染效果,其中以GPU为核心
*显卡的几大品牌大家都知道吧/ww

并列与显卡的,什么声卡,网卡之类的顾名思议了,它们没有被明确定义属于什么设备。

软件系统

计算机软件系统分为操作系统和应用软件,这里重点讲操作系统(太tm喜欢考了)

操作系统

操作系统的作用是控制和协调计算机及外部设备,支持应用软件的运行。
常见(常考)操作系统:
Windows系列:Windows98,Windows2000,WindowsXP,WindowsVista,Windows7,Windows8,Windows8.1,Windows10,Windows11等
Unix和类Unix:MacOS,Linux大家族

*有时CSP会考一下大家的知识面,于是就考察某些软件的跨平台性或者说考察Linux甚至DOS系统的操作,这种SB题大家自求多福

计算机网络系统

互联网的出现相当于让计算机有了互相交流的能力,如今我们对Internet已经习以为常,但网络系统的架构还需要我们了解。

根据ISO(International Standardization Organization,国际标准化组织)制定的OSI(Open System Interconnection,开放式系统互联)参考模型,这只是一个标准,只要符合这个标准的计算机在物理上连接起来,就可以实现数据传输。

OSI的参考模型分为七层(从上到下):
应用层,表示层,会话层,传输层,网络层,链路层,物理层

而Internet中则规定了IP/TCP五层模型(从上直下):
应用层,传输层,网络层,链路层,物理层

在这五层模型中,每层都有各自的网络协议,以下是常见的

应用层

应用层的常见协议有:
HTTP协议(Hyper Text Transfer Protocal):超文本传输协议
Telnet协议:远程终端协议
FTP协议(File Transfer Protocal):文件传输协议
DNS协议(Domain Name System):域名系统协议
除此之外还有很多,但不怎么考。
*顺便提一下HTTP的状态码,常见的404就是HTTP协议的一部分

传输层

传输层常见的就俩带恶人:
TCP协议(Transmission Control Protocal):传输控制协议
UDP协议(User Datagram Protocal):用户数据报协议

两大传输层协议都有各自的特点

TCP协议特点

最显著的特点就是三次握手,非常的稳定安全,使用范围极广。
但三次握手对网络资源的需求相对较高,效率有所下降

UDP协议特点

名字非常奇怪的UDP协议效率非常高,但没有经过验证,链路不一定安全,有可能遭到攻击。但UDP传输字节小,速度很快。

网络层

网络层的协议可以说是千奇百怪哪个层不是,我们着重讲IP协议

IP协议

即Internet Protocol,这是IP/TCP模型中最重要的部分,它提供了一种可靠的寻址方式。

IP地址:互联网中每个网络的每台主机都分配了IP地址。
IPv4:曾经的IP地址是32位的,占四个字节,具体写作 xxx.xxx.xxx.xxx(不是这咋还识别成连接了?点不开的,别点了),其中的xxx是十进制数,在0~255之间。
IPv6:因为IP地址短缺,所以人们设计出IPv6来一劳永逸地解决了这个问题,IPv6由128位组成,写作16进制数,由冒号隔开,例如:
xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx

邮件相关协议

单独讲一下常考的邮件相关协议,包括
SMTP协议(Simple Mail Transfer Protocal):简单邮件传输协议(发邮件协议)
MIME协议(Multipurpose Internet Mail Extensions):电子邮件拓展协议
IMAP协议(Internet Message Access Protocol):交互邮件访问协议(邮件访问协议)
POP协议(Post Office Protocol):邮件服务器协议(现在是POP3,即POP协议第三版,这是种收邮件协议)

*互联网相关硬件设备有Modem(调制解调器),路由器,网卡等
*关于邮箱地址和域名写法这种用过互联网的人都知道的东西我就懒得写了

各大程序语言特征

编程语言自然是信息科学中的纸和笔。

编程语言的分类

要分类肯定有不止一种方法啦/ww

运行方式

分为编译运行和解释运行。

编译运行即编写好代码后通过编译器生成目标程序,然后运行目标程序
解释运行即输入一行代码就执行一行,在项目极大的今天有很大用武之地。

编译性语言有:C/C++,Pascal等
解释性语言有:PHP,Java,JavaScript,Python等(看到数量差距了吗,知道该怎么蒙了吧)

编程思想

从编程思想上分为面向对象和面向过程,但有的语言其实是都能用的。
这俩玩意的概念就不写了,初赛前复习这个也来不及。
面向过程的程序语言有:C,Pascal
面向对象的程序语言有:(C++),(python?),Java,C#

EX人的数学部分

进制转化

虽然说这是小学知识,但CSP也太tm喜欢考这个了吧

具体转换方法就不讲了,摁算就完了(时间没那么紧吧)

二进制

一个有符号的整数存在计算机里是通过补码来存的

原码即直接转化为二进制后填上符号
反码即对负数的每一位取反,符号位除外
补码即反码加一

组合数学概述

两大原理

这里指的是加法原理和乘法原理

加法原理

加法原理即把同阶段的不同的情况相加,举个形象的例子:

从一个城市到另一个城市,有 n n n条公路,同时又有 m m m条铁路,则总共有 n + m n+m n+m种方法

乘法原理

乘法原理即把不同阶段的选择数相乘,举个例子

从a城市经过b城市到c城市,从a到b有 n n n条路,从c到b有 m m m条路,则从a经过b到c有 n ∗ m n*m nm条路径

排列数和组合数

下面我们了解一下组合数学的两大基本运算

C n m C_{n}^{m} Cnm表示在 m m m不同的物体中 n n n选择n个的方案数,叫做组合数,有

C n m = n ! m ! ( n − m ) ! C_{n}^{m}=\frac{n!}{m!(n-m)!} Cnm=m!(nm)!n!

A n m A_{n}^{m} Anm表示在 m m m不同的物体中 n n n选择n个排成序列的方案数,叫做排列数,有

A n m = n ! ( n − m ) ! A_{n}^{m}=\frac{n!}{(n-m)!} Anm=(nm)!n!

这样我们就解决了两个最基本的问题

下面我们来看一下原理(我用容易理解的方法讲一下):

先看排列数 A n m A_{n}^{m} Anm,对于待选的序列,第一项有 n n n个选择,第二项有 n − 1 n-1 n1个,一次类推,第 m m m项有 n − m + 1 n-m+1 nm+1个,根据乘法原理,把它们相乘,总共即为从 n n n乘到 n − m + 1 n-m+1 nm+1,也就是, A n m = n ! ( n − m ) ! A_{n}^{m}=\frac{n!}{(n-m)!} Anm=(nm)!n!

下面再看组合数 C n m C_{n}^{m} Cnm,它和排列数的区别在于排列数区分了物品的顺序,而组合数没有,那么就可以直接把有序转化成无序,即 C n m = A n m m ! C_{n}^{m}=\frac{A_{n}^{m}}{m!} Cnm=m!Anm,代入得 C n m = n ! m ! ( n − m ) ! C_{n}^{m}=\frac{n!}{m!(n-m)!} Cnm=m!(nm)!n!

其他实用的数

各个伟大的前辈们已经为我们整理出了一套完整的组合数学体系,其中除组合数和排列数外,还有其他的数,全部与排列组合有关

Catalan数

我没看到Catalan数的标准表示法,就自己随便写吧

首先我们来看一组题目(也可以想想为什么是一组)

已知一个凸n边型,众所周知,它可以划分为n-1个三角形,求有多少种划分方法

已知一棵二叉树,有n个节点,求这课二叉树有几种情况(注意二叉树区分左右子树)

有n个序列依次进栈,求有多少种合法的出栈序列

一个长度为n的序列全部由1和-1组成,要求多少个序列满足所有前缀和为非负数

由于OIer对二叉树的喜爱与赞美之情我们从第二个问题入手
令当前问题的答案为 h n h_n hn,显然,我们必须要选一个根节点,剩下的节点就被分成左子树和右子树,于是我们得到递推式:
h n = ∑ i = 0 n − 1 h i h n − i − 1 ( h 0 = h 1 = 1 ) h_n=\sum_{i=0}^{n-1} h_ih_{n-i-1} \left(h_0=h_1=1\right) hn=i=0n1hihni1(h0=h1=1)

这就是Catalan数的递推式,显然,只要符合这个递推式就是Catalan数,我们代入剩下的问题就知道了——其实这几个问题的答案完全相同

同时我们还可以得到一些其他公式:
一阶递推公式: h n = 4 n − 2 n + 1 h n − 1 h_n=\frac{4n-2}{n+1}h_{n-1} hn=n+14n2hn1
一个通项公式: h n = C n 2 n − C n + 1 2 n h_n=C_n^{2n}-C_{n+1}^{2n} hn=Cn2nCn+12n
另一个更常用的通项公式: h n = 1 n + 1 C n 2 n h_n=\frac{1}{n+1}C_n^{2n} hn=n+11Cn2n

以下是推导:

我们可以通过同一个问题两个解法的转换来获得Catalan数的通项公式。
对于第三个问题,我们设合法的序列个数为 h n h_n hn,不合法的序列为 u n u_n un
显然有:
h n + u n = C n 2 n h_n+u_n=C_n^{2n} hn+un=Cn2n
若括号序列的最短的不合法的前缀长度是 k k k,显然 k k k是奇数且这个前缀由 k / 2 + 1 k/2+1 k/2+1个-1和 k / 2 k/2 k/2个1组成,同时第 k k k个值是-1。

如果我们把这 k k k个数,得到了一个由 n + 1 n+1 n+1个-1和 n − 1 n-1 n1个1组成的序列,显然这个取反操作是可逆的(找大于0的前缀和并且取反即可),那么不合法的序列和由 n + 1 n+1 n+1个-1和 n − 1 n-1 n1个1组成的序列就是一一对应的,因此
u n = C n + 1 2 n u_n=C_{n+1}^{2n} un=Cn+12n
相减可以得到:
h n = C n 2 n − C n + 1 2 n h_n=C_n^{2n}-C_{n+1}^{2n} hn=Cn2nCn+12n
稍稍转化一下可以得到:
h n = 1 n + 1 C n 2 n h_n=\frac{1}{n+1}C_n^{2n} hn=n+11Cn2n
然后一阶递推公式就显而易见了,直接用通项公式减一下就行。

第一类Stiring数

定义很简单,表示把n个元素划分成m个非空循环排列集合的方案数。
记为 s n m s_n^m snm

直接先看递推式吧:
分两种情况:
这个元素若取,答案就是 ( n − 1 ) s n − 1 m (n-1)s_{n-1}^m (n1)sn1m
若不取,答案就是 s n − 1 m − 1 s_{n-1}^{m-1} sn1m1
根据加法原理直接相加得到:
s n m = s n − 1 m − 1 + ( n − 1 ) s n − 1 m s_n^m=s_{n-1}^{m-1}+(n-1)s_{n-1}^m snm=sn1m1+(n1)sn1m

第二类Stiring数

定义也非常简单,表示把n个元素划分成m个非空集合的方案数。
记为 S n m S_n^m Snm

还是直接先看递推式吧:
分两种情况:
这个元素若取,答案就是 m S n − 1 m mS_{n-1}^m mSn1m
若不取,答案就是 S n − 1 m − 1 S_{n-1}^{m-1} Sn1m1
根据加法原理直接相加得到:
S n m = S n − 1 m − 1 + m S n − 1 m S_n^m=S_{n-1}^{m-1}+mS_{n-1}^m Snm=Sn1m1+mSn1m

Bell数

表示把n个元素划分成若干个非空集合的方案数。
记为 B n B_n Bn

显然有
B n = ∑ k = 1 n S n k B_n=\sum_{k=1}^{n}S_n^k Bn=k=1nSnk
我真不知道这玩意有什么用,就只是一个求和吗?

*以上摘自我自己的博客,剩下一部分可以在那里查看

容斥原理

若有全集 S S S,且有 A i ∈ S ( i = 1 , 2 , 3...... n − 1 , n , n ≥ 2 ) A_i\in S(i=1,2,3......n-1,n,n \geq 2) AiS(i=1,2,3......n1,n,n2)

∣ ⋃ i = 1 n A i ∣ = ∑ k = 1 n ( − 1 ) k − 1 ∑ 1 ≥ i 1 < i 2 < i 3 < . . . . . . < i k ≥ n ∣ ⋂ j = 1 k A i j ∣ |\bigcup_{i=1}^{n} A_i|=\sum_{k=1}^{n}(-1)^{k-1}\sum_{1\geq i_1<i_2<i_3<......<i_k\geq n}|\bigcap_{j=1}^{k}A_{i_j}| i=1nAi=k=1n(1)k11i1<i2<i3<......<iknj=1kAij
可以形象的理解为把所以的加起来,再减去重复的部分,再加回去多减的部分,以此类推

算法与数据结构内容(偏C++)

众所周知,程序由算法和数据结构组成,那么我们来看一下常用(常考)的算法和数据结构。

算法

CSP常见算法有很多,以下由我自己整理而来:

二分
什么是二分

二分即把问题折半来快速找到答案。例如以下的问题

已知 n n n个数,分别为 a 1 , a 2 , a 3 . . . a n a_1,a_2,a_3...a_n a1,a2,a3...an a i < = a i + 1 a_i<=a_{i+1} ai<=ai+1
给出 x x x,把 x x x插入 a a a中,使得 a a a仍然有序,求 x x x能插入的第一个位置。
数据范围: 1 < = n < = 1 0 5 1<=n<=10^5 1<=n<=105

这是一道经典的二分题

这里讲一下二分查找的概念:

首先,我们知道答案肯定在 a 1 a_1 a1 a n a_n an之间(废话+1

然后,我们对最中间那个点进行判断,可以直接得出我们要找的位置是在左半边还是右半边。

然后我们循环这一操作:

#include<bits/stdc++.h>
using namespace std;
int n,x;
int a[100005];
int main(){
    scanf("%d%d",&n,&x);
    for(int i=1;i<=n;i++){
        scanf("%d",a+i);
    }
    int l=1,r=n,mid;       //l为左边界,r为右边界,mid为当前点
    while(l<r){            //区间长度大于1时继续二分
        mid=(l+r)>>1;      //获取中间点
        if(a[mid]>=x){     //判断:中间点小于等于x
            r=mid;         //答案处于左半段
        }
        else{
            l=mid+1;       //否则答案处于右半段
        }
    }
    printf("%d",l);       //此时l=r,即为答案
    return 0;
}

(然后你就A了一道非常水的题)

简易二分写法

由于二分法非常非常常用,C++甚至有一个专门的函数(所以刚才的代码只是练练手)

这个伟大的函数即lower_bound它的格式是:lower_bound(a,a+n,x),其中a是数组名,n是数组长度,相信有基础的同学都知道这里的a是数组的开始地址,a+n是结束地址的下一个,x就是要查找的数,请注意,这个函数的返回值是一个地址,而如果你想知道下标,需要减去开始地址,也就是lower_bound(a,a+n,x)-a

通过这个函数就可以写出一个非常之短的代码:

#include<bits/stdc++.h>
using namespace std;
int n,x;
int a[100005];
int main(){
    scanf("%d%d",&n,&x);
    for(int i=1;i<=n;i++){
        scanf("%d",a+i);
    }
    printf("%d",lower_bound(a,a+n,x)-a);
    return 0;
}

某著名OIer说过(别问我,我也不知道是谁):

二分不是一种特定的算法,而是一种思想,这种思想在各种地方都有涉及,它使得时间复杂度上画上了一个精美的log

有了二分的思想,我们就可以来写一个可爱的线段树二分答案了。

二分答案,其实就是在不断缩小答案的区间,可以达到带log的复杂度,二分查找要求数组有序,二分答案则要求答案具有单调性,具体来说:若x>y且y对应的值为b,x对应的值为a,则一定有a>b

同时,我们注意到二分答案一般用来求最值问题,标志词:最大值最小,最小值最大

同时,还存在另外一种二分答案,即实数二分,它的思想与一般二分相同,但通常用来求解一个高次方程或者一些奇奇怪怪的带小数的问题

贪心

贪心也是一种思想,即对于当前状态做出目前看来最好的决策,思路就这样,但正确性需要根据题目证明

倍增

这破玩意应该初赛不会考

枚举

这个大概不需要讲了吧。

递归和DFS

递归即通过C++中函数的自调用来缩小问题规模并返回问题答案,一个递归必须要有递归边界。

DFS每次选择一种策略往下走,直到发现无法得到答案就回溯,可以达到遍历答案范围的效果。

优化方式:可行性剪枝,记忆化搜索(快成DP了),双头DFS

BFS

BFS即每次往所有决策方向走一步,然后通过队列来维护可能得到答案的状态。

BFS显然可以通过优先队列进行优化,也就是每次把较优的状态排到最前面,这就是A*算法。

其他优化方式:可行性剪枝,双头BFS,01BFS

动态规划

这tm是初赛怎么可能考DP

数据结构

数据结构是描述数据之间相互关系的结构
数据结构分为两大类:线性的和非线性的

线性数据结构

线性数据结构主要有数组,链表等,其中链表简直是CSP的亲儿子。

非线性数据结构

常见的就是树和图

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值