因为失去,所以明白。|

Code_AC

园龄:3年粉丝:5关注:3

CSP初赛复习

一.存储知识:

1.存储:

编码:
比特(bit):编码最小的单位。
字节(byte):存储的最小单位。

2.存储单位的转化:

1 KB = 1024 Byte
1 MB = 1024 KB
1 GB = 1024 MB
1 TB = 1024 GB

3.常见的变量类型的存储大小:

1个 int = 4个 Bytes
1个 (unsigned) long long = 8个 Bytes(unsigned long long 不存负数,存非负数是long long 的两倍)
1个 bool = 1个 Byte
1个 char = 1个 Byte
1个 float = 4个 Bytes
1个 double = 8个 Bytes

二.计算机系统的组成:

硬件系统(hardware)+软件系统(software)。

1.硬件系统:

(1):硬件系统包括主机CPU内存...)以及外接设备输入输出设备等)。

(2):内存分为 RAM(可读写存储器,掉电之后数据清除) 、ROM(只可读存储器,掉电之后数据保留) 和 Cache(高速缓冲存储器,为了适应CPU的高速计算) 三种。

(3):register(寄存器)是CPU里的一个小区域,用来存变量。一般变量存在内存,而 register 可以将变量存到CPU里去,以达到加快运行速度的目的,但一般用于存大量重复的变量,例如循环变量:for(register int i=1;i<=n;i++)之类的。

2.软件系统:

软件系统包括操作系统(Linux、Windows、Mac等)以及应用软件(APP)。

三.进制转化:

(1)十进制转 m 进制——短除法:
如图示:

(2) m 进制转十进制——逐位乘后求和:
如:
(10110)2=1×24+0×23+1×22+1×21+0×20=(14)10

四.位运算和位移操作:

1.位运算(支持各种运算率):

优先级:括号 > 四则运算 > 逻辑运算 > 位运算

(1):按位取反,符号~,将一个整数在二进制下逐位取反。
(2):按位与,符号&,将两个整数在二进制下对齐个位逐位比较,数码同为 1 则为 1,否则为 0
(3):按位或,符号|,将两个整数在二进制下对齐个位逐位比较,数码同位有 1 则为 1,否则为 0
(4):按位异或,符号^/xor,将两个整数在二进制下对齐个位逐位比较,数码不同则为 1,否则为 0

2.位移操作:
(1):左移: 符号<<,左移一位相当于 ×2
(2):右移: 符号>>,右移一位相当于 ×12

五.编码:

(1):编码包括原码反码补码

(2)原码:正负用符号位区分,正数第一位为 0,后接数值,负数则为 1
eg: 5 原码为 0 1015 原码为 1 101

(3)反码:正数的反码就是原码,负数的反码是符号位不变,数值部分取反。
eg: 5 反码为 1 010

(4)补码:正数的补码还是本身,负数的补码是反码 +1

例题:在8位二进制补码中,10101011 表示十进制下的_____?

ans: -85。

六.数据结构:

(1):初赛常考:线性数据结构树形数据结构图类数据结构

(2)线性数据结构: 数组(包括静态数组和动态数组)、队列(先进先出)、(后进先出)、链表(一环扣一环、无法直接访问任意元素)。

栈常考进出栈顺序及前后缀表达式。
前缀表达式:指将四则运算的符号放在最前面,两个数值放在最后面的表达式。
后缀表达式:指将四则运算的符号放在最后面,两个数值放在最前面的表达式。

例题:
ab×c+d×(fe) 的前缀表达式: +  a×b c×df e
ab×c+d×(fe) 的后缀表达式:a b c× d f e × +

(3)树的概念:
树是一种特殊的图,所有结点连通,且 n 个点 n1 条边,树中一定没有环。
在树的结点中,包含父节点、子节点(相对关系)。
根节点是没有父节点的节点,根据是否约定根节点,分为有根树(约定了根节点或边有向的树)或无根树(没有约定根节点且边无向的树)。
叶节点是没有子节点的节点。

(4)特殊的树形结构:
二叉树:对于每个节点,最多只有两个子节点的树。
完全二叉树:除了最后一层,是一颗完美二叉树,且最后一层的节点尽量靠左分布的二叉树。
二叉搜索树:对于任意一个节点 x,其左子树中的权值均不超过 x 的权值,其右子树中的节点权值均超过 x 的权值的二叉树。

(5)二叉树中的一些性质:
树的深度(高度):描述一棵树的节点层数,需要约定根节点是 0 还是 1

二叉树中的数量性质:
1.若深度从 1 计算,则二叉树第 i 层上最多有节点 2i1 个。
2.:若深度从 1 计算,则深度为 h 的二叉树最多有 2h1 个节点
3.:若深度从 1 计算,那么 n 个节点的二叉树深度至多为 n,至少为 logn+1
4.:所有的二叉树都可以直接用数组来存储,若节点编号为 i,则下标也为 i,且左孩子为 i×2,右孩子为 i×2+1

(6)树的遍历:
1.前序遍历(根左右):对于每个节点 x,满足先输出 x,再输出 x 的左孩子,最后输出 x 的右孩子。
2.中序遍历(左根右):对于每个节点 x,满足先输出 x 的左孩子,再输出 x,最后输出 x 的右孩子。
3.后序遍历(左右根):对于每个节点 x,满足先输出 x 的左孩子,再输出 x 的右孩子,最后输出 x
4.层序遍历:从上到下,从左到右。
5.由二叉树的形态可以唯一得到遍历顺序,反之不行,但 先序+中序后序+中序 可以唯一确定二叉树的形态。

代码实现:

#include<bits/stdc++.h>
using namespace std;
struct Node
{
int lc,rc;
}a[MAXN];
inline void dfs1(int x)//前序遍历
{
if(x==0)
return;
printf("%d\n",x);
dfs1(a[x].lc);
dfs1(a[x].rc);
return;
}
inline void dfs2(int x)//中序遍历
{
if(x==0)
return;
dfs2(a[x].lc);
printf("%d\n",x);
dfs2(a[x].rc);
return;
}
inline void dfs3(int x)//后序遍历
{
if(x==0)
return;
dfs3(a[x].lc);
dfs3(a[x].rc);
printf("%d\n",x);
return;
}
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
int n;
cin>>n;
for(register int i=1;i<=n;i++)
cin>>a[i].lc>>a[i].rc;
dfs1(1);//均以1为根
dfs2(1);
dfs3(1);
return 0;
}

例题 P1030 求先序排列

Code

#include<bits/stdc++.h>
using namespace std;
inline void dfs(string z,string h)
{
if(z.size()==0)
return;
char rt=h[h.size()-1];
int p=z.find(rt);
cout<<rt;
dfs(z.substr(0,p),h.substr(0,p));
dfs(z.substr(p+1),h.substr(p,h.size()-p-1));
return;
}
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
string z,h;
cin>>z>>h;
dfs(z,h);
return 0;
}

例题 P1827 美国血统 American Heritage

Code

#include <bits/stdc++.h>
using namespace std;
string a,b;
inline void dfs(int x,int y,int p,int q)
{
if(x>y || p>q)
return;
else
{
int i=b.find(a[x]);
dfs(x+1,x+i-p,p,i-1);
dfs(x+i-p+1,y,i+1,q);
cout<<a[x];
}
}
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
cin>>b>>a;
int len=a.length()-1;
dfs(0,len,0,len);
return 0;
}

(7)图的概念:
由点和线构成的网络。

(8)图的分类:
有四种方式:
1.可分为有向图(边有向或有箭头)和无向图(边无向或无箭头)。
2.可分为有权图(边有权重)和无权图(边没有权重)。
3.可分为有环图(存在至少一个环)和无环图(不存在环)。
4.可分为稀疏图(点多边少)和稠密图(边多点少、边很密集)。

(9)图顶点的度数:
1.有向图:分为入度(一个点被多少箭头指向)和出度(一个点指出的箭头数量)。

2.无向图:一个点连接的边的数量(无向图不分入度出度),

(10)图的连通性:
若图中有点 x 能够找到一条路径到达 y,则称 xy 连通。

完全图:图中的每一个点都与其余所有点有直接连边。

对于有 n 个点的无向完全图,其边数为 n×(n1)2

对于有 n 个点的有向完全图,其边数为 n×(n1)

(11)图的存储:
邻接矩阵,设二维数组 gi,j 表示点 i 指向点 j 的一条边。
邻接链表,设动态数组vector<int>nbr[105];
比如 25 有一条边,那么nbr[2].push_back(5)

也可用链式前向星:

struct edge
{
int to,nxt,len;
}e[MAXN<<1];
int head[MAXN],cnt;
inline void add(int x,int y,int z)//从点x到点y连一条权值为z的边
{
e[++cnt].to=y;
e[cnt].len=z;
e[cnt].nxt=head[x];
head[x]=cnt;
return;
}

七.排序算法:

(1)冒泡排序:时间复杂度 O(n2),稳定。
(2)选择排序:时间复杂度 O(n2),不稳定。
(3)插入排序:时间复杂度 O(n2)(可以做到 O(n)),稳定。

八.数学相关的问题:

(1)加法原理:做一件事情,有 n 种做法,第 i 种做法有 ai 种方式,则完成这件事情有 i=1nai 种不同的方法。

(2)乘法原理:做一件事情,有 n 个步骤,第 i 个步骤有 ai 种方式,则完成这件事情有 i=1nai 种不同的方法。

(3)排列数公式:n 个数种选 m 个数构成 1 组有序的排列,方案数为:

Anm=n!(nm)!

(4)组合数公式:n 个数种选 m 个数构成 1 组无序的组合,方案数为:

Cnm=AnmAmm=n!(nm)! m!

例1: 8 个人排成一队。
1.要求甲乙两人必须相邻。
解:

A77×2

2.甲乙不相邻。
解:

A88(A77×2)

3.甲乙相邻但是与丙不相邻。
解:

A77×2A66×4

4.甲乙相邻且丙丁相邻。
解:

A66×4

例2:有人射击,开了 8 枪,命中 4 枪,恰好有 3 枪连续命中的方案有多少?

解:在五个空中选取 2 个排列,即 A52

(5)卡特兰数(Catalan):
Cn 表示在 n+2 条边的凸多边形中,可以画 n1 条不相交的对角线,将该多边形分成 n 个三角形。

Cn 也可表示所有在 n×n 格点中不越过对角线的单调路径的个数。

递推式:

Cn=k=0n1Ck×Cnk1

通项公式一:

Cn=1n+1×(n2n)=(2n)!(n+1)! n!

通项公式二:

Cn=(2nn)(2nn+1) (n1)

通项公式二其实就是把通项公式一拆开。

那么我们这里来证一下第二个:

根据定义,合法的路径不能越过对角线。那么我们考虑利用总方案数 C2nn 减去不合法的方案数。

这里的黄色线和绿色线连接而成的路径代表一条不合法的路径,我们把路径第一次超越对角线的点(点 L)到终点(点 A)的路径沿粉色线条(对角线向上平移 1 个单位得到)对称。得到了蓝色的路径。显然,这里的黄色路径和蓝色路径是对应的。

而之所以选择“向上平移 1 个单位”的意义就是在任何情况下接触这条线就会变成不合法路径。

容易证明,所有不合法的路径和所有从原点到A'点的路径都是一一对应的。所以不合法的路径条数就是从原点到A'的路径条数 C2nn1

证明如下:

因为这个关系是可逆的(通过操作后的路径能得出操作前的路径),所以显然所有不合法的路径和所有从原点到 A 点的路径都是一一对应的。

这样就得出了前面提到的卡特兰数第二个通项公式:

Cn=(2nn)(2nn+1) (n1)

那么现在我们来应用一下:

例1:有一个算式,包含 n 运算符及 n+1 个运算数值,要求在算式中加上 1 对括号,求不同的运算顺序有多少种?

解:这种题目基本用卡特兰数解决,结果就是一个二叉树。

例2:n 个节点的二叉树,不同的形态有多少种?

解:很明显我们分别考虑左右子树,那显然就是卡特兰数的递推式。

放球问题:n 个球放入 m 个盒子中:
1.球同,盒子相同,不允许空盒子;(只能穷举法)
2.球同,盒子相同,允许空盒子;(只能穷举法)

3.球同,盒子不同,不允许空盒子;(隔板法)Cn1m1
4.球同,盒子不同,允许空盒子;(隔板法)Cn+m1m1

5.球不同,盒子相同,不允许空盒子;(第二类斯特林数)
6.球不同,盒子相同,允许空盒子。(第二类斯特林数)

第二类斯特林数:{nm} 表示 n 个不同元素分为 m 个集合的方案数。

递推式:

{nm}={n1m1}+m×{n1m}

说白了就是第 n 行第 m 个数等于它上一行第 m1 个数加上一行第 m 个数乘 m

通项公式:

{nm}=1m!i=0(1)mi(mi)in

第一类斯特林数:[nm] 表示 n 个不同元素分为 m 个圆排列的方案数

有标号的第一类斯特林数:s(n,m)=(1)nm[nm]

递推式:

[nm]=[n1m1]+(n1)[n1m]

即新建一个圆排列,或者插入前面 n1 个元素中任意一个的后面。

那么显然,有标号的就是:

[nm]=[n1m1](n1)[n1m]

生成函数有些复杂,这里就不说了。

本文作者:Code_AC

本文链接:https://www.cnblogs.com/code-ac/p/16557739.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   Code_AC  阅读(759)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起