*基础算法(1)
持续更新···
1.模拟
P5731 【深基5.习6】蛇形⽅阵
【题⽬描述】
给出⼀个不⼤于
9
的正整数
n
,输出
n
×
n
的蛇形⽅阵。
从左上⻆填上1 开始,顺时针⽅向依次填⼊数字,如同样例所⽰。注意每个数字有都会占⽤ 3个
字符,前⾯使⽤空格补⻬。
【输⼊描述】
输⼊⼀个正整数
n
,含义如题所述。
【输出描述】
输出符合题⽬要求的蛇形矩阵
【⽰例⼀】
输⼊:
4
输出:
1 2 3 4
12 13 14 5
11 16 15 6
10 9 8 7

2.高精度
当数据的值特别⼤,各种类型都存不下的时候,此时就要⽤⾼精度算法来计算加减乘除:
*先用字符串读入这个数,然后用数组逆序存储该数的每⼀位;
*利用数组,模拟加减乘除运算的过程。
⽤代码模拟⼩学列竖式计算加减乘除的过程。
【题⽬描述】
⾼精度加法,相当于
a
+
b
problem,不⽤考虑负数。
【输⼊描述】
分两⾏输⼊。
a
,
b
≤ 10^
500
。
【输出描述】
输出只有⼀⾏,代表
a
+
b
的值。

3.枚举
扫雷:现在棋盘是 n × 2 的,第⼀列⾥⾯某些格⼦是雷,⽽第⼆列没有雷,如下图
【输⼊描述】
第⼀⾏为
N
,第⼆⾏有
N
个数,依次为第⼆列的格⼦中的数。
(1 ≤
N
≤ 10000)
【输出描述】
⼀个数,即第⼀列中雷的摆放⽅案数。
当第⼀列中,第⼀⾏的⼩格⼦的状态确定了之后,其实后续⾏的状态也跟着固定下来。⽽第⼀列中,第⼀⾏的状态要么有雷,要么没有雷,所以最终的答案就在 0, 1, 2
中。 因此,我们枚举第⼀列中,第⼀⾏的两种状态:要么有雷,要么没雷。然后依次计算剩下⾏的值,看看是否能满⾜所给的数据。
4.前缀和
最大子段和
【题⽬描述】
给出⼀个⻓度为
n
的序列
a
,选出其中连续且⾮空的⼀段使得这段和最⼤。
【输⼊描述】
第⼀⾏是⼀个整数,表⽰序列的⻓度
n
。
第⼆⾏有
n
个整数,第
i
个整数表⽰序列的第
i
个数字
a
i
5.差分
【题⽬描述】
给你⼀个⻓度为
n
的正数数组
a
1 2
,
a
, ......,
a
n
接下来对这个数组进⾏ 次操作,每个操作包含三个参数 ,代表将数组 都
加上 。
m l
,
r
,
k a
l l
,
a
+1
, ...,
a
r
k
请输出操作后的数组。
【输⼊描述】
第⼀⾏包含两个整数
n
和
m
。
第⼆⾏包含
n
个整数表⽰
a
1 2
,
a
, ......,
a
n
接下来是
m
⾏,每⾏三个整数,分别代表每次操作的参数
l
,
r
,
k
6.双指针
双指针算法有时候也叫
滑动窗口
,是⼀种优化暴⼒枚举策略的⼿段:
当我们发现在两层 for 循环的暴⼒枚举过程中,两个指针是可以不回退的,此时我们就可以利⽤
两个指针不回退的性质来优化时间复杂度。
因为双指针算法中,两个指针是朝着同⼀个⽅向移动的,因此也叫做同向双指针。
【题⽬描述】
博览馆正在展出由世上最佳的
m
位画家所画的图画。
游客在购买⻔票时必须说明两个数字,a 和b ,代表他要看展览中的第 a幅⾄第b 幅画(包含
a,b)之间的所有图画,⽽⻔票的价钱就是⼀张图画⼀元。
Sept 希望⼊场后可以看到所有名师的图画。当然,他想最⼩化购买⻔票的价格。
请求出他购买⻔票时应选择的
a
,
b
,数据保证⼀定有解。
若存在多组解,输出
a
最⼩的那组。
【输⼊描述】
第⼀⾏两个整数
n
,
m
,分别表⽰博览馆内的图画总数及这些图画是由多少位名师的画所绘画的。
第⼆⾏包含
n
个整数
a
i
,代表画第
i
幅画的名师的编号。
【分析】
进窗⼝: right位置元素记录到统计次数的哈希表中,如果次数是 0变1 ,说明窗⼝内多了「⼀
种」字符,记录⼀下;
判断:当窗⼝内字符种类等于
m
时,窗⼝合法,
right
停⽌右移,接下来需要出窗⼝;
出窗⼝:让 left所指位置的元素在哈希表中的次数减⼀,如果次数是1 变0 ,说明窗⼝内少了
「⼀种」字符,记录⼀下;
更新结果:在判断成⽴时,窗⼝合法,此时更新窗⼝的⼤⼩。

7.二分算法
【题⽬描述】
⽜可乐得到了⼀个⻓度为n 且⾮严格单调递增的序列 a,然⽽这个序列被 q层魔法封印了,其中
第i 层封印的问题包含两个整数xi,yi ,⽜可乐必须正确回答序列中⼤于等于xi 且⼩于等于 yi的数字个数才能够解开该层封印。
⽜可乐觉得这个问题太难了,于是他想请你帮助他解开序列的
q
层封印。
【输⼊描述】
第⼀⾏包含⼀个整数 n,表⽰序列的⻓度
第⼆⾏包含n 个整数,
第三⾏包含⼀个整数q ,代表封印层数。
之后q ⾏,每⾏两个整数xi,yi ,代表该层封印的询问。
【输出描述】
对于每层封印,输出⼀⾏⼀个整数,代表在范围内的数字个数。
*二分过后可能没有这个区间,需要判断一下

7.2二分答案
⼆分答案可以处理⼤部分「最⼤值最⼩」以及「最⼩值最⼤」的问题。如果「解空间」在从⼩到⼤的「变化」过程中,「判断」答案的结果出现「⼆段性」,此时我们就可以「⼆分」这个「解空间」,通过「判断」,找出最优解。
洛谷:砍树........

8.贪心
9.倍增
【题⽬描述】
给你三个整数
a
,
b
,
p
,求
a
b
mod
p
【输⼊描述】
三个⽤空格隔开的整数 a, b 和 p。
【输出描述】
输出⼀⾏⼀个字符串
a^b mod p=s
,其中
a
,
b
,
p
分别为题⽬给定的值,
s
为运算结果。
如何实现这个算法呢,以
a ^
b
为例:
*⼀边提取
b
的⼆进制表⽰中的每⼀位;
*⼀边让
a
=
a
∗
a
,不断变成之前的平⽅(倍增的思想);
*在提取
b
的⼆进制表⽰时,如果这⼀位是
1
,就乘上对应位置的权值。

10.离散化
当题⽬中数据的范围很⼤,但是数据的总量不是很⼤。此时如果需要⽤数据的值来映射数组的下标
时,就可以⽤离散化的思想先预处理⼀下所有的数据,使得每⼀个数据都映射成⼀个较⼩的值。之后再⽤离散化之后的数去处理问题。
⽐如:
[99, 9, 9999, 999999]
离散之后就变成
[2, 1, 3, 4]
。

【输⼊描述】
第⼀⾏⼀个整数,表⽰起⽕的信息条数n 。
接下来n ⾏,每⾏两个整数a,b ,表⽰⼀个着⽕位置的起点和终点(注意:左闭右开)。
对于全部的测试点,保证
1 ≤
n
≤ 2 × 10 ^4, −2 ^31≤
a
<
b
< 2^
31
,且答案⼩于
2^
31
。
【输出描述]
曹操⽓急败坏的把你找来,要你钻⼊⽕海把连环线上着⽕的船只的⻓度统计出来!
给定每个起⽕部分的起点和终点,请你求出燃烧位置的⻓度之和。
这道题的「数据范围」不允许我们直接差分,因为「开不了那么⼤」的数组;即使能开那么⼤
的数组,「时间」也不够⽤。
我们发现,区间的范围虽然很⼤,区间的「个数」却只有
2 × 10
4
级别。此时我们就可以:
1.
先将所有的「区间信息」离散化;
2.
然后在「离散化的基础」上,处理所有的「区间修改」操作;
3.
处理完之后找出「原始数组对应的区间端点」,计算相应的「⻓度」。
