写在前面
一个简略的(NOIp)题高组历年题目复习记录.大部分都有单独写题解,但懒得放(link)了(QwQ).对于想的时候兜了圈子的题打上(*).
(NOIp2018 [4/6])
### 铺设道路 模拟/结论
从左往右扫一遍,扫到高度比前一个大的就累加上两者的高度差.
货币系统 (dp)/背包
考虑从货币系统中去掉不必要的货币,不必要的货币其实就是能被其他货币表示出的货币.货币无限多,可以看成完全背包问题,设(f_i)为数值(i)能否被小于它的数表出.
(*)赛道修建 二分/贪心/树形
最小的最大,容易想到二分,变成判定性问题.再贪心+树形(dp)即可.
发现我已经不会写这个贪心了,于是又回去看了看原来的题解.(copy)一下关键句子:"对于每个结点,把子结点上传的链长加上父与子之间的边权加入(multiset).首先找到值已经大于等于(mid)的,直接累计答案.然后考虑内部匹配,从小到大扫,找到另一个最小的使得两者相加大于等于的值,(mid)删去这俩结点并且累计答案.最后向父结点上传剩余的链里面最长的就行."
旅行 图论/贪心/搜索
首先树的情况做法非常显然,直接从(1)开始,每次贪心地选择能走的结点里字典序最小的走就行,不能走就退回上一城市.
(m=n)的情况,也就是树上有个环,显然这个环上一定有一条边不会被走过,枚举这条边是啥,然后按照树的做就行.
然而发现忘记怎么找环以及删边了(QwQ),又回去看了下以前的(code)然后(get)了,其实是一个比较暴力的方法.环就直接(dfs)找,删边的话就记个全局变量记边的两个端点,按树的情况做的时候强制不走这条边就行.
填数游戏
### 保卫王国
(44pts)的暴力树形(dp)还是很好写的叭.
## $NOIp2017 [5/6]$
### 小凯的疑惑 打表/数学
这题表好打规律也好找(QwQ).证明并不想写了,可以看(gql's blog).
时间复杂度 模拟
模拟题.之前一直觉得自己写不出来这种超级大模拟,也不想写.之前考托腮的考试有一个大模拟,考试嘛当然不得不写了.发现其实慢一点,细心一点也是可以写好的.打算再写一次(QwQ),但不是现在(QwQ).
逛公园 图论/记搜/(dp)
前不久才写的,这题(dp)有点难写,记忆化搜索好写多了.我永远喜欢记搜.
奶酪 并查集
简单题(QwQ),去年就会了.不过我会的应该是个比较暴力的做法:就先(n^2)枚举算(dis),如果相连就加入一个并查集,最后再枚举上表面的洞和下表面的洞,看有没有联通的.
宝藏 状压(dp)
也是前几天才写的(QwQ).由于代价和层数有关,所以直接枚举层和已选集合,再枚举一些点加入,强制它们是下一层的,至于连哪条边,直接暴力枚举取(min)就行.(其实感觉这题做法挺暴力的,但觉得巧妙的一点是,不一定要每一步都算出精确答案,只要最终答案正确就可以了.
列队
好难不会.
## $NOIp2016 [5/6]$
### 玩具谜题 模拟
简单模拟.
天天爱跑步
### 换教室 期望/$dp$
期望(dp).转移有点复杂要细心一点.
组合数问题 前缀和/组合数
观察(k)的取值可以知道这里的组合数(C)不能直接通过公式(C_n^m=frac{n!}{m!(n-m)!}).又因为这里的(n,m)都挺小,所以可以直接递推(C_n^m=C_{n-1}^m+C_{n-1}^{m-1})算.记一个前缀和就行了.
(*)蚯蚓 模拟/单调性
(80pts)的做法是很容易想到的,复杂度是(mlog(n+m)).优化是去掉这个(log),发现题目中隐藏的单调关系就可以不用(priority\_queue)了.注意到先切的蚯蚓的较长部分比后切的长,较短部分也是这样.直接开三个数组,一个存被切过的切是较长的一个,一个存较短的,一个存还每被切过的.每次取三个数组最大的最大就行.
愤怒的小鸟 搜索/状压
两种解法:搜索/状压(dp),都挺好写的.就讲下状压的小优化叭,就是最终要算的是(f_S),对于当前状态(f_i),枚举一个抛物线(j)来转移,当且仅当(j)经过(lowbit(i)).这样优化之后复杂度是(O(Tn2^n)).
对了,还有精度问题要注意,开个(1e-8)的亚子就行.
## $NOIp2015 [6/6]$
### 神奇的幻方 模拟
简单模拟.
(*)信息传递 并查集/搜索
居然不怎么会做这题了(QwQ).
这题其实就是求一个有向图的最小环,最小环算法的复杂度显然是不行的.考虑这题有一个非常特殊的性质就是每个点的出度都为(1).这题主要有俩算法:
1.并查集做法.就每次连一条边就把它们加入一个并查集,再记一个(d_i)表示从(i)开始走到不能走,所走过的点数.对于当前加入的边((u,v)),如果它们同属于一个并查集,也就是说(v)已经有一条路径到(u)了,现在又有一条路径从(u)到(v),这就形成了一个环,环大小为(d_v+1) ;否则就合并(u,v),且维护(d_u=d_v+1).注意到这里的(d)不是这么简单就可以维护得了的,还要改造一下(find)函数来维护.
2.搜索做法.直接搜所有的环.从每个点出发找环,记录走到每个点的时间,如果当前点再走一步就会走到一个标记过的点,那就出现了一个环,环的大小就是现在的时间减去下一个走到的点的时间再(+1).由于每个点至多在一个环里,所以搜过的点没必要再搜,剪枝即可.
$upd on 11.6:$在做一个与这题挺类似的一题的时候,想到了另外一个方法. ( 发现题解里有这个方法只是之前没看$QwQ$,反正讲下.就直接拓扑排序确定哪些点在环上,再遍历每一个环确定它的大小,最后在所有环里取$min$就可以了,复杂度$O(n)$.超级好写$5 min$就过了.
### 斗地主 搜索
我还不会斗地主呢.暴搜+最优性剪枝就可以过.
跳石头 二分
二分板子题.
子串 (dp)
刚做的,不难.唯一要(D)自己的是居然不记得滚动数组了!!
运输计划 二分/树上差分
题意是求将哪条树边变成(0)可以使得给定的路径中,最长的最短.显然考虑二分,对于一个二分值(mid),将长度大于(mid)的路径拎出来,计算每条边被这些路径经过多少次,去掉经过次数最多的边,再看去掉该边后能否满足题意即可(check),计算路径被经过多少次就树上差分下就好.
(NOIp2014 [6/6])
### 生活大爆炸版石头剪刀布 模拟
入门模拟题.
联合权值 树形/贪心/前缀和
以任意结点为根,与一个点距离为(2)的点有它的祖父,孙子,兄弟.前面两个都好算,唯一有点技巧的是兄弟.兄弟这里显然不可以直接枚举着算,考虑用前缀和优化.假设一些兄弟的权值是(x,y,z),那么贡献是(xcdot y +xcdot z+ycdot z),不就是(xcdot y+(x+y)cdot z)嘛.求和就是这样,再看兄弟结点间的联合权值怎么更新最大值,这里贪心一下,直接选两个权值最大的兄弟结点就行.
飞扬的小鸟 (dp)
上周复习背包的时候还复习了这题.考虑(dp),(f_{i,j})表示到位置((i,j))所需的最小点击屏幕数.可以点击屏幕多次上升,说明上升是完全背包.每秒只能下降一定高度,说明下降是(01)背包.
无线网络发射器选址
暴力即正解.
寻找道路
先把所有不满足条件(1)的点去掉,然后直接(dijkstra)即可.怎么判断满不满族条件呢?建反图,从终点(dfs)一遍,记录每个点的入度,再从起点(dfs),记录每个点的出度,如果入度(=)出度,那么就是满足条件(1)的点.
解方程
枚举解,代入方程中检验即可,用秦九韶算法计算.有一个细节是(a_i)太大了,没有办法直接读入,直接再快读里边读边(\%)就行.
## $NOIp2013 [5/6]$
### 转圈游戏 找规律
答案是((x+mcdot 10^k) mod n).
火柴排队 贪心/离散化/逆序对
要得到最小距离显然是第一列中最小的配第二列中最小的,次小配次小..这样推下去.所以可以把序列离散化一下,把第一个序列对应成(1,2,3,..,n),第二个序列依照相对位置得到一个序列,我们的目标就变成了交换第二个序列,使得它变成单调递增的序列.每交换一次,一定是一个大数交换到了后面,也就是逆序对减小了(1),那么答案显然就是逆序对的个数.归并排序或者树状数组都可以求.
积木大赛 模拟/结论
铺设道路.
(*)花匠 (dp)
设(f_{i,0/1})表示考虑到第(i)盆花,这盆花相对上一盆是上升/下降的,保留的最多数目.一个显然的转移是枚举上一盆是什么,取(max)即可.这样可以获得(80pts).
其实总感觉这题和求(LIS)挺像的.所以来想想(LIS)是怎么求的,有一种方法是直接记录当前最长的上升序列,对于扫到的下一个元素(x),若(x)大于当前序列的尾值,就直接将它加入,否则就用(x)来替换选出序列中比它大的第一个元素.这样贪心地替换一定是最优的,因为给后面的选择留出了更多的空间.
再来看这题,先类似地改变下(dp)数组的意义,先只考虑条件(1),(f_{i})表示的是一个合法序列的第(i)个元素是啥.(len)表示当前合法序列的长度.假设(i)元素是波谷,若(h_{i+1}>h_i),那么直接将序列长度(+1)就行,否则,将(i+1)代替(i)成为新的波谷显然是不劣的.由于我们只需要知道当前序列的最后一个元素,所以(f)数组也是不需要的,直接开一个变量存一下就行.然后再来考虑条件(2),和上面类似地做一遍就行.
华容道
还没做呢.
## $NOIp2012 [4/6]$
### Vigenère 密码 模拟
没啥好说.
国王游戏 贪心
发现两个人的位置关系只能影响他们两者的贡献,不会影响到其他人的贡献.所以先只考虑两个人(i,j),设(prod_{k=1}^{i-1}=t).
若(i)在前,则贡献是(max(frac{t}{b_i},frac{tcdot a_i}{b_j}));若(i)在后,则贡献是(max(frac{t}{b_j},frac{tcdot a_j}{b_i})).
考虑(i)在前更优需要满足什么条件.注意到我们现在关心的是这两个(max)再取(max)的数属于前面还是后面.换言之,我们现在关心的是四个元素中最大的元素是谁.
显然(frac{t}{b_i}<frac{tcdot a_j}{b_i},frac{t}{b_j}<frac{tcdot a_i}{b_j}).所以只要知道(frac{tcdot a_j}{b_i})与(frac{tcdot a_i}{b_j})的大小关系就行.现在要(i)在前面更优的条件是(frac{tcdot a_i}{b_j}<frac{tcdot a_j}{b_i}).转化下:(a_icdot b_i<a_jcdot b_j).所以,只要以之为关键字排个序就行.
开车旅行 倍增
暑假有天写了好久都没写出来然后就弃了(QwQ).我这两天会写的!
同余方程 数学
光考试就考了两遍了我当然会了辣(QwQ).(其实我还背不下来每次都要现推
借教室 线段树/二分
首先显然要离散化天数,这样就变成(10^6)级别的了.具体来说有两种方法.
(1.)简单粗暴线段树.直接区间加,维护区间(min)需要的教室数减去有的教室数,若(min<0),就不合法了.
(2.)二分.如果第(x)个人借完教室之后,存在某一天教室数(<0),那么第(x+1,x+2,..)个人借完教室之后,一定存在某天教室数(<0),所以答案具有单调性,可二分.(check)就记一个差分数组,然后直接让前(mid)个人借完教室,再求前缀和看有没有不合法的即可.
疫情控制
还没做(QwQ).
## $NOIp2011 [6/6]$
### 铺地毯 模拟
签到题.
选择客栈 计数
要求一对客栈满足颜色相同且中间有权值不大于(p)的客栈,求这样的客栈对数.
扫描一遍所有的数组,记录一个(sum1_i)表示当前扫到的客栈中色调为(i)的有多少个,(sum2_i)表示色调为(i)且与当前客栈间隔有权值不大于(p)的客栈的数目.扫到一个权值不大于(p)的客栈时就更新所有的(sum2_i).
(Mayan)游戏 搜索/模拟
大模拟,但感觉这题比时间复杂度呆一点,简单一点.
计算系数
首先把(a,b)去掉,显然最后的系数包含一个(a^nb^m).众所周知,((x+y)^k)展开之后的系数是杨辉三角的第(k)行的某个数.所以,求个杨辉三角就行.
然而这题有更优秀的做法,我们只需要杨辉三角上的一个数值就好,没必要推出整个三角.思考杨辉三角还有什么意义?组合数!所以最后答案就是(C_{k}^ncdot a^ncdot b^m).
聪明的质监员
将(S-Y)的绝对值去掉,将问题分为两个部分,一个是(S>Y)时要求(S)越小越好,一个是(S<Y)时要求(S)越大越好.现在我们只考虑第一个问题.显然答案具有单调性,可二分.怎么(check)呢?记录两个前缀数组:(a_i=sum _{w_jgeq W}1),(b_i=sum _{w_jgeq W}w_j).
观光公交 贪心
考虑对一个(D_i)使用加速器给答案的贡献是多少.
具体来说是这样的:首先要坐车到达(D_i)的这些乘客时间肯定会减少,在(D_i)等车的乘客的时间肯定会减少,这取决于车到达的时间是否不早于最后一个乘客到达的时间,假若会使得在(D_i)等车的乘客时间减少,那么又可能会使得(D_{i+1})等车的乘客时间减少,类似的情况.
所以,维护两个数组(arr1_i)和(arr2_i)表示汽车到达(i)的时刻和最后一个乘客到达(i)的时刻.对(D_i)使用一个加速器的贡献就是在([i,j],arr1_j-1>arr2_j-1且arr1_jleq arr2_j).这段区间下车的乘客数目.贪心地选择这样数目最多的(D_i)使用加速器即可.
觉得原来写的(blog)写得挺清楚的.
## $NOIp2010 [4/4]$
### $*$引水入城 记搜
如果能满足要求,那么一个蓄水厂所输送水到的沙漠城市一定是连续的一段.假若只能输送到([l_1,r_1])和([l_2,r_2]),那么显然([r_1+1,l_2-1])这段区间不能有水利设施(因为这个联通块整个高于周围的联通块),与"能满足要求"矛盾,故假设不成立.
设([l_i,r_i])表示能蓄水厂(i)能输水到的沙漠城市区间,用记忆化搜索求出所有的([l_i,r_i]),顺便记录每个沙漠城市是否被覆盖到用来判定有无解.最后就转化成了一个最小线段覆盖问题,贪心做就行.
关押罪犯 二分/二分图/贪心/并查集
显然答案具有可二分性.于是二分这个答案,则怨气值大于(mid)的不能放在同一监狱,二分图染色(check)就好.
还有并查集做法,先按照怨气值从大到小排序.记录每一个罪犯的第一个扫到的发生冲突的罪犯,如果扫到两个罪犯其中一个罪犯的对手有记录的对手,那么就把他们两个分到一个监狱.
机器翻译 模拟
简单模拟.
乌龟棋 (dp)
发现(b)值很小,于是把它记入状态.(f_{i,a,b,c,d})表示走到第(i)个位置,还有卡片(1 a)张,(2 b)张,(3 c)张,(4 d)张最多得到的分数.发现数组开不下,直接将第一位省略掉就好了.
## $NOIp2009 [4/4]$
### 潜伏者 模拟/字符串
简单题,但要认真读题.
(Hankson)的趣味题 数学
(gcd(x,a_0)=a_1 ightarrow gcd(frac{x}{a_1},frac{a_0}{a_1})=1)
(lcm(x,b_0)=b_1 ightarrow gcd(frac{b_1}{x},frac{b_1}{b_0})=1)
直接(O(sqrt b_1))枚举(x),(check x)是否满足(a_1|x,x|b_1)和上面的两个等式,贡献答案,还要算(frac{b_1}{x})的答案.以为自己写了个暴力,结果(AC)了(QwQ).
再讲一个更加优秀的方法.先筛出(sqrt{2cdot 10^9})内的质数然后将(a_0,a_1,b_0,b_1)暴力分解质因数.因为(gcd)是取指数的最小值,(lcm)是取指数的最大值,所以可以对每个质数得出一个可取数量的区间,乘起来就是答案了.
(*)最优贸易 图论/(dfs)/缩点
先缩点把图上的环去掉,然后直接一遍(dfs)更新答案即可.这是一种比较容易想到的方法.下面讲一种更加巧妙且实现更为简单的方法:
设价格为(w_i),记(mi_i)为从(1)到(u)路径上经过的最小的(w),(mx_i)为从(u)到(n)路径上经过的最大的(w),那么若(1)可达(i)且(i)可达(n),就可以用(mx_i-mi_i)更新答案.
维护一个点(i)能不能被(1)到达和能不能到达(n)是可以简单维护的.现在的问题是如何维护(mi_i,mx_i).考虑按(w)从小到大排序的顺序去更新其他点,这样每个点的(mi)最多只被更新一次,(mx_i)也是类似地做. (像这样用一个元素的值去更新其他元素的最小/最大值,都可以考虑排个序变成赋值操作.
靶形数独 搜索
搜索+剪枝.
在此复习下剪枝的几个方法 (算法竞赛上蒯的:
比较常用的:可行性剪枝/最优性剪枝
容易忽略的:优化搜索顺序/记忆化
还有一个没(get)的:排除等效冗余.在搜索树上如果能够判定从当前结点沿着某几条不同的分支到达的子树是等效的,那么只需要对其中的一条执行搜索. (这个我还没太(get).
(NOIp2008 [4/4])
### 苯小猴 模拟
入门题,送分送到位了(QwQ).
传纸条 (dp)
经典(dp)题.两条路径一起走,设(f_{x_1,y_1,x_2,y_2})表示第一条路径走到((x_1,y_1)),第二条路径走到((x_2,y_2))时,两条路径的好心程度之和最大是多少.直接枚举下一步往哪走转移,注意不能走至同一个格子.
为啥这样做可以保证((x_2,y_2))一定不会再走到((x_1,y_1))走过的位置呢?因为每次只能向下或向右走,所以(x_1+y_1=x_2+y_2),((x_2,y_2))再走一步到达的格子的横纵坐标之和一定是(x_1+y_1+1),而((x_1,y_1))走过的地方的横纵坐标之和小于该值,所以可以保证.有个更简单的解释就是,每个时刻可能在的地方都是一条与横坐标成(45)度角的一条直线上,这些直线互相不重合.
显然(dp)中有一维可以由别的维度推出,可以省略.
火柴棒等式 搜索/枚举
开始感觉这题直接搜不一定能过,因为理论上(n=24)时,可以组成(11111),枚举下就(1e10)了.于是写了个搜发现(n=24)时只能组成(30261)个数,把这些数按照用的火柴棒数拍个序,枚举两个加数,及时(break)循环是可以过的.
双栈排序 栈/二分图
先观察可以单栈排序的条件是啥,具体来说:(forall i<j<k),都没有(p_k<p_i<p_j).简单整理一下,就是不存在二元组((i,j))满足上述条件.
再来看双栈排序.如果将序列分成两个子序列使得它们分别可以单栈排序,那么这个序列就可以双栈排序.将所有的二元组((i,j))建出来,二分图染色即可.最后要注意对操作的顺序贪心,注意细节.
(NOIp2007 [4/4])
### 统计数字 $set/$排序
用个(set or map)维护一下不就好了.看了下标签,其实可以直接排序算就行.
字符串的展开 模拟
去年暑假考过这题.看懂题模拟就成.
矩阵取数游戏 (dp)
注意到行与行之间是互相独立的,可以分别计算每一行的最大贡献,加起来就是答案了.
对于单独的一行,是个典型的区间(dp).设(f_{i,j})表示一行只剩下([i,j])这个区间还没有取的最大贡献,转移就枚举这次取数是取(i)还是(j)去更新(f_{i-1,j})或者(f_{i,j-1}).最后答案是(max{f_{i,i}+2^ncdot a_i}).
树网的核 树形/枚举
先考虑暴力做法叭.
首先可以对每个结点都(dfs)一遍求出所有的(d_{i,j}),这里取个(max)就知道了树的直径.把(d_{u,v}=)直径的(u)记录一下,预处理完了之后对每个这样的(u dfs)一遍,维护一个栈,里面存当前路径经过的点,找到一个点(v)使得(d_{u,v}=)直径时,枚举栈中的元素组成的路径,用这个路径去更新答案.这里有一个贪心的地方,就是假设((u,v))是一条合法路径,((u,x))也是一条合法路径,且((u,v)in(u,x)),那么((u,x))一定不会比((u,v))劣.
结果就(AC)辣?感觉是(n^4)的复杂度(QwQ).加强版的这题在这里,我的代码可以过(nleq 3000).
对了,还有就是感觉这里超多(min)和(max),一定要仔细搞清楚再写.
(NOIp2006 [4/4])
### 能量项链 $dp$
典型的区间(dp),与合并石子大同小异.
金明的预算方案 (dp)/背包
简单的有依赖的背包问题,由于最多只有两个附件且附件不再有附件,所以不需要树形背包就可做.典型的树形背包题应该是[洛谷(2014)选课].不过这题还是要注意循环的顺序,应该要把枚举附件的循环放在最里面.
作业调度方案 模拟
直接模拟.
(*2)^(k)进制数 (dp)
设(f_{i,j})表示(2^k)进制数的第(i)位选了(j)的方案数.
(f_{i,j}=sum_{x=j+1}^{2^k-1}f_{i-1,x})
第一维可以滚掉,转移可以前缀和优化,记一个(s_{i,j})表示第(i)位选了不小于(j)的数的方案数.
(WA)了好久(QwQ),为啥函数里传递的数组不能用(memset qaq).
## $NOIp2005 [4/4]$
### 谁拿了最多奖学金 模拟
入门模拟题,去年学结构体的例题.
过河
又没懂题(kk).原来跳跃过河不一定要跳在石头上面.
简单(dp): (f_i)表示跳到位置(i)所经过的最少石头数,可以获得(30pts).
路径压缩( 好神仙吖(QwQ) :
假设现在可以走的步数是(p)和(p+1),那么(gcd(p,p+1)=1),套上小凯的疑惑的结论可以知道(pcdot (p+1)-(p+p+1))之后的点都是可以用(p)和(p+1)表示出来的.
所以直接把两个石头之间间距超过(tcdot (t-1))的变成这么多就行.
### $*$篝火晚会 结论/思维
题面也太锅的了叭,其实这(b)个位置可以不连续(QwQ).
首先判断一下有没有解.我最开始想的是如果有两个以上的人想和同一个人相邻,那么无解.事实上,这并不能涵盖所有的情况,应该是如果(a)想和(b)相邻,而(b)不想和(a)相邻,这种一厢情愿的情况是不合法的,而且它涵盖了我上面说的情况.
考虑最优策略.假设现在的序列和目标序列有(k)的元素不相同,我们可以通过若干次命令,这些命令的总代价为(k)来达到目的.具体来说,将每个不同位置上的数向它的目标位置连边,一定为形成若干个环,每次对一个环操作就是最优策略.
最后状态的环显然是已知的,但是我们不知道(1)和(2)位置上是啥,如果知道了这两个位置上的数,那么所有位置上的数就都确定下来了.枚举这俩位置上的数是啥,一共有(2n)种可能,再按照上面的结论计算不同位置的个数就行.然而这样复杂度是(O(n^2))的.
把枚举(1,2)的位置抽象成这样一个问题:有两个嵌套的环,里面的环是(1,2,3,...,n),外面的环是(p_1,p_2,p_3,..,p_n),现在要旋转外面的环使得两个环对应位置上不同的数尽量的少. (注意,因为方向的问题,外面的环实质上是有两种的,但这里只讨论一种,另外同理).先随便排一个外环,对每个位置求出要到达它的目标位置,需要外环顺时针(逆也行,反正钦定一个)旋转多少个位置,开个桶存旋转(x)个位置有多少个位置会对齐.取桶里的最大值就行.
### 等价表达式 模拟
感觉是一个和时间复杂度差不多难度的模拟题.
注意这题有一个坑点是可能输入里括号是不匹配的,这时就直接(GG)了.另外一个我觉得有点奇怪的地方就是我感觉我每行都读了换行,但是仍然要在读入字符串的时候加(if(c=='r')c=getchar()).
这题我写的比较呆.首先一个大家都能想到的地方就是给(a)赋值,计算值比较.我是开了一个栈,每扫到一个做括号就加入栈,有括号就计算栈顶元素到该右括号之间的值.这样就去掉了括号的限制,然后对序列扫三遍,分别计算乘方,乘法,和加减.
其实可以考虑这样做:递归计算优先级最低的符号左右两边的算式,最后合并.还要考虑括号的情况,具体来说记一个(p_i)表示(i)位置上符号的优先级,在括号里的优先级要高于括号外的.放下(gql)小朋友的代码.
## $NOIp2004 [4/4]$
津津的储蓄计划 模拟
它真的是道入门题,成为了我在洛谷做的第(5)道红题.
合并果子 (dp)
区间(dp)入门题.
合唱队形 (dp)
记(f_i)为(1)到(i)的最长上升子序列的长度,(g_i)为(i)到(n)的最长下降子序列的长度.分别求出,答案就是(max{f_i+g_i}).
虫食算 搜索
直接搜每个字母代表了了什么数字再(check).
优化下搜索顺序,使得可行性剪枝发挥最大的作用.按照令(p_s)表示字母(s)在三个字符串中出现的最末的位置,按照(p)降序排的顺序搜.
这题正解竟然是高斯消元(QwQ).然而并不想看了.
(NOIp2003 [3/4])
### 神经网络 拓扑排序/模拟
拓扑排序模拟下就行.
侦探推理 模拟/字符串
暑假有天刚了好久这题.最后还是(T)成了(80pts).我会写这题的!
加分二叉树 (dp)
注意到一个子树在中序遍历的序列里是连续的一段区间(这句话很重要吖不要忘了(QwQ)).所以这题其实是个区间(dp).
设(f_{i,j})为区间([i,j])组成一棵树的最大加分,由于要输出前序遍历,所以还要记一个(p_{i,j})表示([i,j])树以(p_{i,j})为根时加分最大.按照区间(dp)套路转移就行,枚举根是哪个,从小区间转移到大区间.
传染病控制
其实看起来很贪心的亚子,但是又想不出贪心策略.那就搜索叭(QwQ),简单搜索就能过.
## $NOIp2002 [4/4]$
### 均分纸牌 模拟/贪心
将所有的(A_i)减掉(frac{sum A_i}{n}),得到第(i)堆还要丢掉/得到多少牌,要丢就直接丢到(i+1)堆,要得到就从(i+1)堆拿.直接这样做就行.其实觉得这题还是挺巧妙的?在考场上可能没那么容易想到(QwQ).
字符变换 搜索/字符串
直接(bfs),开个(map)记下搜过的就不要搜了.
正好学了下(string)的一些函数 ( 之前只知道(length() QwQ).用上函数就简单多了,对了有个要注意的地方就是替换并不一定是替换第一个出现的位置,也要枚举后面的.
string a,b;
a.insert(pos,b) //插入
a.erase(pos,n) //删除[pos,pos+n-1]之间的字符
a.clear()
a.replace(pos,n,b) //将[pos,pos+n-1]之间的字符替换为b
注意replace里n的含义!不是[pos,n].
a.find(b) //从前往后找b第一次出现的位置并返回
a.find(b,pos) //从pos开始找b第一次出现的位置并返回
//倒着找为rfind 没找到返回的是string::npos
a.find_first_of(b);a.find_first_of(b,pos);找到与b中的任意一个元素就返回
a.find_last_of(b);...//倒着找
a.find_first_not_of(b);//找到不是b的任意一个元素并返回
a.substr(pos)//返回a里从pos到最后这段子
a.substr(pos1,pos2)//返回a中[pos1,pos2]这段子串
a=to_string(123)//将int转为string
自由落体
物理题.计算出在小球们落到高度为(k)时小车的位置,和小球们落到高度(0)时小车的位置,在这两个位置之间的小球就是能被接受到的小球.
(upd:)最后我还是选择了(O(n))枚举判断,感觉这样判断要简单些不容易错些.
(*)矩形覆盖 搜索
直接枚举矩形的左下角和右上角再(check)就可以了叭.矩形的端点并不一定是平面上的点吖!所以这个做法(GG)了.
直接搜哪些点在同一个矩形,判断合法,最优性剪枝就行.
(NOIp2001 [4/4])
### 一元三次方程求解 枚举/数学/二分
看根的范围再看精度要求,枚举枚举就过了.
其实也可以用提示里的方法.因为根与根之间的绝对值(geq 1).换言之,就是每个长度为(1)的区间内(除端点)至多只有一解.于是就可以猜想直接对于每个单位区间二分下答案就行.
然而我觉得很疑惑就是如果像二次函数那样,可能(f(l)>0,f(r)>0),但(xin(l,r),f(x)=0)这亚子就不能二分算了.被(gql)小朋友(D:)你真的不知道三次函数长什么亚子嘛??然后给我画了个,确实不会有我说的那种情况.知道我数学有多差了叭.
数的划分 搜索
搜索入门题,记得可行性剪枝.
统计单词个数
和[子串]有一丝相似?考虑(dp).
设(f_{i,j})表示前(i)个字符分了(j)段包含的最大单词数.转移显然就是枚举第(i-1)段的起始位置(k).
现在的问题就是如何计算一段([k+1,i])之间有多少个单词.这个可以(O(n^3))预处理出(g_{i,j})表示([i,j])之间有多少个单词.具体来说,预处理一个(q_{i,0})指从位置(i)开始匹配有没有单词,(q_{i,1})指从位置(i)开始匹配,匹配到的单词的右界最少是多少.这样预处理(g_{i,j})就枚举(kin[i,j]),若(q_{k,0}=1)且(q_{k,1}leq j),就(++g_{i,j}).
(Car)的旅行路线
求出每个城市的第四个飞机场的坐标,然后直接按照题目要求连边跑最短路就行.
(WA)了一发,我才知道原来给一个(double)赋值为(-0),输出是(-0.000).
(NOIp2000 [4/4])
### 进制转换 数学/进制
先只讨论(N)为正数的情况.先将(|r|)进制下该数的表示求出来,再考虑怎么转成(-r)进制.发现在奇数位,由于指数是偶数,所以可以先不动.假设第(i(2|i))位上的值为(x),也就是这个数要加上(|r|^{i-1}cdot x),其实就是要加上(|r|^{i-1}cdot (|r|+x-|r|)=|r|^i-|r|^{i-1}cdot(|r|-x)).于是将这一位变成(|r|-x),下一位加上(1).
那么(N)为负数怎么处理呢?先求出它绝对值的(r)进制表示,然后在奇数位和上面一样变动就行.
乘积最大 (dp)
首先要预处理一个(g_{i,j})表示(i)到(j)组成的数是多少.然后就是典型的区间(dp)了,(f_{i,j})表示前(i)个位置放了(j)个乘号的最大答案,转移就枚举第(j)的乘号的前一个位置(k)就成.
单词接龙 搜索/字符串
去年觉得这题超级无敌巨难(QwQ).
预处理(f_{i,j})表示(i,j)两个单词的中间重合部分的长度,如果是包含关系,则定义为(0).然后就可以直接开搜了,记录当前字符串中最后一个单词是啥,维护每个单词用了多少个就行.
方格取数 (dp)
和传纸条唯一不同的地方在于两条路径可以重复,只是重复部分只能算一次贡献.
(NOIp1999 [4/4])
### 拦截导弹 $dp$/贪心
真的是很经典的题目吖.
要求最长不严格下降子序列的长度和把序列分成若干个不下降子序列的最少数量.
前者(nlogn)做法就设(f_i)表示当前最长序列的第(i)个导弹的高度,二分查找替换维护即可.后者就是个贪心,记下当前有的所有下降序列的末尾值,对于一个数(x),用比(x)大的最小的拦截它,如果都比它小,就开个新的.
回文数 模拟
入门题.我记得去年考过这题,然后因为某些原因我的程序没进循环只判了第一个和最后一个相不相等,还获得了(90pts)的好成绩(QwQ).
旅行家的预算 贪心
先不考虑油箱大小的限制,那么先找到(min{P_i}),然后依次找前面比它大的最小的数...一直这样找下去可以得到一个单调递减的序列,每次只在这个序列里的加油站加油,加油的量就刚好加到到达下一个加油站.这样显然是最优的.
然而现在有一个油箱的限制,上面的做法可能不合法.然后我(GG)了(QwQ).
从起点开始,在能走的范围内找到(P)最小的,若这个(P)小于当前加油站的(P),那当前加油站就加油刚好能走到那个加油站,否则就直接加满.注意下一个就到终点的情况要特判下.对了还要在最开始判掉无解.
邮票面值设计 搜索/(dp)
我前几天才知道原来这题所有的算法都好假,数据是(7 7),(7 8)这样的都跑不过.似乎只能跑过(n+kleq 9)的所有数据.
还是讲下这题的'假'搜索做法.
就直接搜选的(n)种邮票的面值,具体来说从小到大搜每个数,在搜当前数之前求下最大连续到了什么地方,则当前搜的数不能超过最大连续值(+1).
怎么求当前最大连续到什么地方了呢?发现这里就特别像去年的[货币系统],但是这里有贴(k)张邮票的限制.设(f_i)表示拼出(i)所需要的最小邮票数.完全背包转移(注意确定上下界的问题)最后枚举(check)即可.
(NOIp1998 [3/3])
### 拼数 字符串/排序/搜索
从前往后贪心地选取首位数字最大的,若首位数字相等就扫描后面的位置,选择最大的.若两个数(x,y), (x)的长度小于(y),在(x)的位数内和(y)都是相等的,就看下一个候选数的首字母与(y)在(x)的位数+1的位置的关系.
(QwQ)发现上面的贪心真的很难想清楚,因为最后一个判断可以嵌套然后我不会了.于是瞎写了个搜索因为是(NOIp)数据所以(AC)辣.
讲下题解做法,觉得好神奇啊,只要写个(cmp)函数排下序就行,如下:
(bool cmp(string a,string b){return a+b>b+a;})
车站 找规律/递推
设第二站上车的人数为(x),手推一下每一站上车人数减去下车人数的序列是:(a,0,a,x,a+x,a+2x,2a+3x,3a+5x...)设(f_i)表示第(i)站上车人数减下车人数,发现(f_i=f_{i-2}+f_{i-1},igeq 5).于是随便推下就行.
(*)进制位 搜索
题目没讲不同字母代表的数不同差评.
好现在我们都知道字母代表的数不同了,那么一个行数列数为(n+1)的表代表的一定是(n)进制.可以反证法证明,就不证了.如果是考试可以猜结论(QwQ).
直接搜索每一个字母代表的是啥然后(check)就成,连剪枝都不要,因为搜索复杂度就是对的.
## $NOIp1997 [1/1]$
### 棋盘问题 搜索
注意一个数不能填两次.预处理下(pri_i)表示(i)是否为素数.然后直接开搜,先搜第一行和第一列,从小数搜到大数,第一个搜到的解就是最优解.(为啥?其实这个是我猜的(QwQ).但过了.
其实感觉上面很不对的亚子,最好还是搜完,加个最优性剪枝就成.