很难很累,但还是必须去做
任务清单
一轮真题
二轮真题
题目选讲
2019 CSP-J1
1. 常识积累
- T1:中国的国家顶级域名是
.cn - T3:一个 32 位整形变量占用 4 个字节
- T5:折半查找(二分)时,找到目标最多需要 log(n) 次
- T6:链表在 插入和删除 中表现优异,在 查询 中表现较差,也不必事先估计存储空间
- T9:100 以内的最大质数是 97
- T15:计算机科学领域的最高奖是 图灵奖
2. 数论计算
T7(整数划分)
把 个同样的球放在 个同样的袋子里,允许有的袋子空着不放,问共有多少种不同的分法?
提示:如果 个球都放在一个袋子里,无论是哪个袋子,都只算同一种分法。
解析:直接暴力枚举,然后去重就没了
T12(鸽巢原理)
一副纸牌除掉大小王有 52 张牌,四种花色,每种花色 13 张。
假设从这 52 张牌中随机抽取 13 张牌,则至少()张牌的花色一致。
解析:设在 12 张牌中,每种花色 3 张(最坏情况),那么再多一张一定会有 4 张牌的花色一致
T13(乘法原理)
—些数字可以颠倒过来看,例如 0,1,8 颠倒过来还是本身,6 颠倒过来是 9,9 颠倒过来看还是 6,其他数字颠倒过来都不构成数字。
类似的,一些多位数也可以颠倒过来看,比如 106 颠倒过来是 901。假设某个城市的车牌只由 5 位数字组成,每一位都可以取 0 到 9。
请问这个城市最多有多少个车牌倒过来恰好还是原来的车牌?()
解析:在 0,1,8,6,9 中选择,然后判断回文数(因为顺序颠倒之后还要求是原来的车牌),那么我们只需要考虑第 1,2,3 位就好了
但是颠倒之后 6 和 9 会互换,所以第 3 位不能是 6 和 9
所以第一、二位有 5 种选择,第三位有 3 种选择,根据乘法原理可得最终方案数为
2024 CSP-J2 T2(大模拟)
题号:Luogu P11228
题意
给出 行 列的地图,机器人初始位于 ,朝向是 ,每次根据当前朝向朝对应方向步进,如果下一步越界或不是空地,那就向右转。问进行 次操作之后,机器人走过的格子数量(包括起始位置)
解析
依题意模拟,用一个集合记录走过的格子,当机器人操作数等于 时,输出机器人走过的格子数量,然后结束跑下一组数据即可。
代码
1 |
|
2021 CSP-J2 T3(字符串+模拟)
题意
给你 台机器,分为服务器和客户端。
难点 然后判断服务器和客户端的 IP(IPv4+端口)是否合法然后服务器的 IP 必须保持唯一
然后客户端要和对应的 IP 建立连接,按题意输出就好了
解析
对于验证 IP 的正确性问题,我们可以将 IP 利用 string 存起来,然后利用 sscanf 这一利器
sscanf 的用法:sscanf(源字符串,格式字符串,目标变量);
下面是一个示例,从 date 字符串中按照 %d/%d/%d %d:%d:%d 的格式,分别提取到变量 year month day hour minute second 中:
sscanf(date,"%d/%d/%d %d:%d:%d",&year,&month,&day,&hour,&minute,&second);
sscanf 的返回值是 成功提取变量的数量,例如上面那个例子中的正确返回值应该是 6,如果返回值不等于 6,就说明提取失败。
那么让我们带入到 IP 中,我们需要提取 5 个整数,只要返回值不是 5,立刻返回 false 即可
又看到字符串的长度 ,所以最大的整数不超过 17 位,用 long long 存就可以。
所以我们的一条判断条件就是:
if(sscanf(ip.c_str(),"%lld.%lld.%lld.%lld:%lld",&a,&b,&c,&d,&e)!=5) return false;
现在我们提取到了每个整数,接下来就是判断是否合法了,依照题目判断范围即可,这一步不多说了
然后我们要解决前导 0 的问题。我们可以把我们提取出来的整数拼接回去,拼成一个正确的 IP 地址,然后和读入进来的 IP 进行比较,如果相同就证明没有前导 0。
我们可以开一个 string,然后加起来就好了。但是因为你的整数化成字符串有点麻烦,你就可以使用 to_string() 函数,这属于 STL 的一种,在 C++11 被引入,OI 使用没问题。
string now_ip=to_string(a)+'.'+to_string(b)+'.'+to_string(c)+'.'+to_string(d)+':'+to_string(e);
验证 IP 解决了,下面就是连接问题。
连接过程中,你需要根据客户端请求的 IP 寻找服务器 IP,然后输出对应的 ID 即可。
这一步我们可以使用 map 或 unordered_map 来解决,这可以减少内存的占用。
我们建立 unordered_map<string,bool> server_ip_exist 来表示服务器 IP 是否存在,unordered_map<string,int> server_id 来表示服务器 IP 对应的 ID。
然后在读入的时候先看看当前输入的 IP 是否存在,然后就可以标记存在和记录 ID 了。
代码
1 |
|
知识积累
与或非运算
这些操作都要在 二进制下 完成
- 按位与:
&:每一位都必须是1才会得到1,否则是0 - 按位或:
|:每一位只要有一个是1就会得到1 - 按位非:
~:每一位取反 - 按位异或:
^:每一位相同为0,不同为1
在数学上, 和 && 是一样的, 和 || 是一样的, 和 ! 是一样的
这是 逻辑运算符,不要混淆
(重难点)进制转换
转换技巧:遇到 x 进制转 y 进制,可以先把 x 进制转为 10 进制,再转为 y 进制
x 进制转 10 进制
按位展开,乘权相加例如 转 10 进制:
在上面的式子中, 其实就是十进制里面的 ,这不用多说
如果是带小数的部分,要 乘负权相加
例如 转 10 进制
10 进制转 x 进制
不断除以 x,余数倒着写,商循环利用例如 转 16 进制
如果是带小数的转换,整数部分还是和上面相同的,小数部分要 不断乘以 x,商取整,顺着写,小数循环利用
例如 转 8 进制
那么我们先算整数部分:
然后算小数部分:
最后让我们加起来,得到了
如果题目中需要更高的精度,那就继续乘以 8,直到小数部分为 0
常用数字的进制转换
| 十进制 | 二进制 | 八进制 | 十六进制 |
|---|---|---|---|
| 0 | 0000 | 0 | 0 |
| 1 | 0001 | 1 | 1 |
| 2 | 0010 | 2 | 2 |
| … | … | … | … |
| 7 | 0111 | 17 | 7 |
| 8 | 1000 | 10 | 8 |
| … | … | … | … |
| 15 | 1111 | 17 | F |
| 16 | 10000 | 20 | 10 |
| … | … | … | … |
二进制编码
- 原码:用 最高位 作为符号位,0是正数,1是负数,符号位之后是这个十进制数的绝对值的二进制,存在 -0 的问题,所以不用
- 反码:正数和原码相同;负数符号位不变,剩余的 在原码基础上按位取反
- 补码:正数和原码相同;负数就是反码+1(忽略符号位进位)
GCD 和 LCM
- GCD:Greatest Common Divisor,最大公约数
- LCM:Least Common Multiple,最小公倍数
- GCD 和 LCM 之间的关系:
- 在 C++14 标准之后(OI 可用),你可以通过
algorithm库中的std::__gcd(int,int)和std::__lcm(int,int)来计算 GCD 和 LCM - 在 CSP 一轮考场上,可以直接带入选项中的数值去尝试
(重难点)排列与组合
排列
概念:集合 由 个不同的元素组成,取出其中的 个,与顺序有关 的情况数为 ,计算公式为:
例如从 5 个元素中选出 2 个,求有多少种方案(数字相同但顺序不同也算另一种)
那么一共有
种方案
当 时,
组合
概念:集合 由 个不同的元素组成,取出其中的 个,与顺序无关 的情况数为 ,计算公式为:
例如从 5 个元素中选出 2 个,求有多少种方案(数字相同但顺序不同只算做同一种)
那么一共有
种方案
当 时,
排列与组合的联系
有重复的排列
给出具有 个对象的集合 ,选出 个,可以重复选择
从第 1 个位置到第 个位置,每个位置有 种选择,那么一共有 种方案
有重复的组合(插板法)
给出具有 个对象的集合 ,选出 个,可以重复选择,与顺序无关
最终方案数是
(重难点)小球与盒子
你有 个小球,要放到 个盒子里,每个盒子可以放多个小球,
可辨别的小球与可辨别的盒子
最终方案数是
不可辨别的小球与可辨别的盒子
盒子可以是空的:
盒子不能是空的:
剩下两种严重超纲,不记(涉及到第二类斯特林数和很多的分类讨论)
(易考)树的遍历
给出前序遍历和中序遍历,可以唯一确定一棵二叉树
给出后序遍历和中序遍历,可以唯一确定一棵二叉树
步骤
- 前序遍历的第一个元素是根节点,后序遍历的最后一个元素是根节点
- 在中序遍历中找到根节点,它的左边是左子树,右边是右子树
- 递归构建左子树和右子树
示例
前序:ABDECFG
中序:DBEAFCG
- 首先确定
A为根节点 - 在中序遍历中找到
A,它的左边DBE是左子树,右边FCG是右子树 - 在前序
BDE和CFG中得到后序遍历DBE和CFG - 接上根节点
A,得到后序遍历DBECFGA
也可以去 2019 CSP-J1 T14 练习
(易考)单位换算
M = 1e6,K = 1e3
1B(yte) = 8bit
二进制存储空间换算
1TiB = 2e10GiB = 2e20MiB = 2e30KiB = 2e40B = 2e43bit
十进制存储空间换算
1TB = 1e3GB = 1e6MB = 1e9KB = 1e12B = 8*1e12bit
文件存储空间
图片存储空间:
视频存储空间:
(单位根据码率单位而定)
帧率缩写 fps,码率 bps
NOI 历史
- 第一届 NOI:1984,今年(NOI2025)第 41 届
- 第一届 IOI:1989
- 我国 2000 举办第 12 届 IOI
- 第一届 NOIP:1995,2019 暂停一届
- 第一届 CSP:2019
网络
OSI 七层模型
- 物理层:光纤、中继器
- 数据链链路层:网卡、交换机、以太网
- 网络层:IP、ICMP
- 传输层:TCP、UDP
- 会话层:SSL、TLS
- 表示层:LPP
- 应用层:HTTP、FTP、SMTP、POP3
协议
HTTP:超文本传输协议
FTP:文件传输协议
SMTP:收发电子邮件
POP3:接收电子邮件
TCP:三次握手(A->B 质询在线,B->A 返回在线,A->B 返回确认收到)
IP 地址
IPv4:x.x.x.x(0<=x<=255)32bit 4B
- A类地址:
1.0.0.1~127.255.255.254 - B类地址:
128.0.0.1~191.255.255.254 - C类地址:
192.0.0.1~223.255.255.254
IPv6:X:X:X:X:X:X:X:X(0000<=X<=FFFF)64bit 8B
排序
算法信息
n=等待排序的个数,w=数据值域
| 算法名称 | 平均时间 | 最坏时间 | 是否稳定 |
|---|---|---|---|
| 冒泡排序 | true | ||
| 选择排序 | false | ||
| 插入排序 | true | ||
| 计数排序 | true | ||
| 归并排序 | true | ||
| 快速排序 | false |
快速排序原理
使用递归原理
在 a[l]~a[r] 中选择一个基准 x
使用双指针将所有 a[i] < x 交换到 x 左侧,a[i] > x 交换到 x 右侧
快速排序通过双指针交换后,将一个大的排序问题划分为了两个子区间排序的小问题
所以期望复杂度
如果选择第一个数作为基准,序列有序,每次序列长度只减少 1
所以最坏复杂度
std::sort
由 algorithm 头文件提供,属于 STL
在数据范围较小的情况下,使用了堆排序等技术
数据结构
链表
优点:插入删除
缺点:读取 n=链表元素个数
示例:
1 | [prev = NULL, id = 1, value = 114, next = 514] |
图的存储
邻接矩阵
优点:查询边权
缺点:对于稀疏图,浪费空间
邻接表
优点:空间复杂度
缺点:查询边权
树
有 个节点 条边的无向连通图
完整二叉树:每个节点的子节点数量都是 0 或 2
运算优先级
自增/自减 执行顺序
++x 先增加 x 的值,然后送出使用
x++ 先送出使用,然后增加 x 的值
x++ + ++x
这属于 未定义行为(Undefined Behavior, UB),在不同的编译器上可以解释为任何值。
这可能导致本地通过,评测报错
可以通过 -Wall 参数找到所有的警告
计算原理
容斥原理/减法法则
如果一个任务可以通过 种方法执行,还可以通过 种另一类方法执行,那么执行这个任务的方法数量是
也就是说,集合 ,与并集 ,满足
鸽巢原理
如果 个或更多的物体放入 个盒子,那么至少有一个盒子包含了 2 个或更多的物体
广义鸽巢原理
如果 个物体放入 个盒子,那么至少有一个盒子至少包含了 个物体
高级语言分类
- 面向过程:以函数为基本程序结构:C,Pascal,Fortran
- 面向对象:以类为基本程序结构:C++,Java,Python
- 编译性:执行前用连接器生成可执行文件:C++
- 解释性:一边用解释器翻译,一边运行代码:Python,JS,Ruby
- Java:编译 + 解释混合
计算机历史
- 第一台计算机 - ENIAC
- 有存储功能 - EDVAC
- 冯诺依曼 - 存储结构
- 图灵 - 测试
- 阿达罗福莱斯 - 计算机程序的创始人
- 马文·明斯基、约翰·麦卡西 - 对 AI 杰出贡献
- 香农 - 信息论
哈夫曼树
// TODO