NOIP2009-2018简要题解
口胡警告
NOIP2009
潜伏者
模拟
Hankson 的趣味题
对四个数\(a_0,a_1,b_0,b_1\)分解质因数,结果序列分别记为\(\{p1^{b1}\},\{p2^{b2}\},\{p3^{b3}\},\{p4^{b4}\}\),然后对于每种质因子\(p_i\),它的指数\(a_i\)要满足\(b2_i\le a_i\le b4_i\),然后如果\(b1_i\neq b2_i\),那么\(a_i\)只能为\(b2_i\),如果\(b3_i\neq b4_i\),那么\(a_i\)只能为\(b4_i\),然后就能知道每种质因数的取值范围,乘法原理乘起来就是答案
最优贸易
\(Tarjan\)缩点,然后\(DAG\)上dp,记录\(mi_x\)表示一个强连通分量以及前面能到它的点中最小点权,\(ans_x\)表示最大的点取在\(x\)里面的答案,用\(x\)里面最大点权\(-mi_x\)更新\(ans_x\),最后答案为能到\(n\)所在强连通分量的\(ans\)最小值
靶形数独
考虑爆搜,剪枝就先填能填的数比较小的格子,然后可以还写一个估价函数为剩下没填的数不考虑数独限制的尽可能填入权值大的格子的答案
NOIP2010
机器翻译
用队列模拟
乌龟棋
设\(f_{i,j,k,l}\)表示用了\(i\)个\(4\)\(j\)个\(3\)\(k\)个\(2\)\(i\)个\(4\)最大权值,转移枚举下一步选什么
关押罪犯
注意到大于答案所有边都不能出现,所以考虑从大往小加边,然后一条边两个端点染成不同颜色,如果加入一条边后不能满足所有边端点不同色,那么这条边权值就是答案,用带权并查集维护二分图染色即可
引水入城
一个上面的点能影响的一定是下面一排点的一个区间,否则如果中间有不能影响到的点,那么其他点也影响不到,这时候就不合法.然后变成了选出最少的区间覆盖所有点的问题,dp即可
NOIP2011
铺地毯
后面的地毯会覆盖前面的,所以从后往前枚举地毯是否包含这个点
选择客栈
从前往后扫,计算以某个点为右端点的区间个数,那么这个点的左端点是和它同色的,并且这中间包含一个权值\(\le p\)的点,所以维护每种颜色的合法左端点数量\(c_i\),具体是先把当前点压入栈中,如果当前点权值\(\le p\)就把栈弹空,更新\(c_i\).注意不要统计到自己的贡献
Mayan游戏
按照字典序枚举操作爆搜,注意实现的时候一定要先掉落完再消除,可以判掉交换两个相同元素的操作
计算系数
二项式定理\((a+b)^n=\sum_{i=0}^{n}\binom{n}{i}a^ib^{n-i}\)
聪明的质检员
由于\(Y\)随着\(W\)的增加单调不增,所以二分\(W\)到\(Y\)靠近\(S\)的位置,然后前缀和优化统计
观光公交
贪心考虑,选择影响人数最多的路加速,一个路能影响一个人当且仅当这个终点在这个路后面,并且到那个人终点的这一段过程中没有别的点满足公交到达那个点时间\(\le\)那个点人最晚出现时间.我们把公交到达那个点时间\(\le\)那个点人最晚出现时间的点看做断点,然后序列分成若干段,在每一段开头加速可以影响到终点在这一段的人,然后堆维护影响人数最多的段,线段树维护区间最小点权,每个点权值为\(\max(0,\)公交到达时间\(-\)那个点人最晚出现时间\()\),然后每次拿堆顶的段的开头的路操作,操作次数为\(\min(\)总的剩余操作次数,那个路的剩余操作次数,段内线段树上最小值\()\),使得这一段线段树最小值为\(0\)了或者开头的路的\(D_i\)为0了就把这一段分成两段
NOIP2012
Vigenère 密码
模拟
国王游戏
考虑交换相邻两个数,显然只会影响这两个数的贡献,推导后可得到把\(a_ib_i\)小的放前面更优,然后模拟一遍,实现高精即可
开车旅行
按照题意先处理出每个点开始让\(A/B\)走一步到的点,然后就可以\(O(n^2+qn)\)暴力模拟,优化的话倍增处理出从每个点开始先让\(A/B\)走\(2^k\)步到的点,以及先让\(A/B\)走\(2^k\)步过程中\(A/B\)走的路程和总路程,然后倍增跳统计
同余方程
\(\text{exgcd}\)求解\(ax+by=1\)的最小非负\(x\)
借教室
线段树维护区间最小值,每次区间减法,最小值\(<0\)时输出答案
疫情控制
二分最终答案,然后所有军队先尽量往根走,走不到就到能到的深度最浅的点打标记,再dfs整棵树,如果一个点所有儿子被标记那么这个点也被标记,然后就是用一些军队匹配根节点没被标记的儿子,按照军队能走的步数排序,依次考虑,如果这个军队从下面走上来经过的根节点儿子没被匹配就匹配,否则匹配需要步数最小的儿子
NOIP2013
转圈游戏
快速幂
火柴游戏
可以发现第一排最大的要匹配第二排最大的,第一排次大的要匹配第二排次大的...然后搞出\(n\)二元组\((a_i,b_i)\),按\(a_i\)升序排序,答案就是排序后\(b\)的逆序对个数
货车运输
从大往小加边,如果一个边加入后会成环,那么这条边不走显然不会更劣,那么就相当于求出最大生成树,然后就是查询路径最小值,倍增即可
积木大赛
记差分数组为\(d_i=a_i-a_{i-1}\),答案为\(\sum \max(d_i,0)\),证明可以手动模拟
花匠
枚举第一个数是作为峰还是谷,然后扫一遍序列如果序列末尾为峰,然后下一个数更小那么序列长度+1,下一个数就作为谷,否则把下一个数替换掉当前的峰,这样更有利于后面的选择
华容道
一个局面只和目标棋子和空位位置有关,空格可以自由移动,目标棋子要移动那么就要把空位在不经过目标棋子的前提下移到目标棋子周围四格,预处理\(g_{i,j,k,x,y}\)表示\((x,y)\)不经过\((i,j)\)的情况下移到\((i,j)\)的\(k\)方向的最短路,然后求解时设\(f_{i,j,k}\)表示目标棋子在\((i,j)\),空格在棋子的\(k\)方向的最短路,然后转移大概是\(f_{i,j,k}\)通过\(g\)转移到\(f_{i,j,k'}\),表示空格移动,\(f_{i,j,k}\)转移到\(f_{i',j',inv(k)}\)表示棋子移动
NOIP2014
生活大爆炸版石头剪刀布
模拟
联合权值
枚举每个点,那么可以贡献的点对的端点为和这个点相邻的点,然后记最大值次大值做第一问,记前缀和做第二问
飞扬的小鸟
设\(f_{i,j}\)表示到达\((i,j)\)的最小点击次数,转移有从\(f_{i-1,j+y_i}\)转移,以及\(f_{i-1,j-x_i},f_{i,j-x_i}\),因为一次可以点击多次,注意最上面一行可以从\(j\in[max(1,m-x_i),m]\)转移,以及要先转移\(x_i\)再转移\(y_i\)
无线网络发射器选址
二维前缀和
寻找道路
预处理每个点是否能到\(n\),然后就可以枚举出边判断每个点是否可走,那就用可走的点跑最短路
解方程
枚举\(i\),用秦九韶算法解出\(\sum a_j i^j\),对于\(a_i\)可对大质数取模
NOIP2015
神奇的幻方
模拟
信息传递
图一定是若干基环树,答案为最小环长
斗地主
不考虑单顺双顺三顺,其他的牌的方案可以\(dp\)解决,设\(f_{i,j,k,l}\)表示个数为\(4\)的牌有\(i\)种,个数为\(3\)的牌有\(j\)种,个数为\(2\)的牌有\(k\)种,个数为\(1\)的牌有\(l\)种的最小次数,转移枚举下一次打什么牌,取\(x\)张相同的牌的话可以新增一种牌,也可以选前面用过的(也就是某一维-1,往前\(x\)维+1).然后搜索顺子的方案,剩下的拍方案就是\(f\)数组
代码(代码中没考虑大小王不能成对子)
跳石头
二分答案\(mid\),然后就是移最少石头,使得相邻距离\(\ge mid\),这个可以从开始扫,如果这个石头到上一个没移的石头距离\(<mid\)就移走,注意最后一个石头必须放
子串
设\(f_{i,j,k,0/1}\)表示扫到\(A\)的第\(i\)位,匹配到\(B\)的第\(j\)位,在\(A\)上匹配了\(k\)个子串,当前是否在匹配,转移枚举下一位匹配状态,注意如果当前在匹配可以从下一位开始匹配一个新的\(A\)子串
运输计划
二分最终答案,然后所有长度\(\ge mid\)的路径都要被减去一个值,那么要选的边必须被所有不合法路径覆盖,那么差分处理,选出被所有路径覆盖的最长边check即可
NOIP2016
玩具谜题
模拟(下标加减)
天天爱跑步
一个人的路径可以看成往上走和往下走,往上走的时候\(de_x+\)时刻\(ti\)为定值,往下走时\(de_x-ti\)为定值,所以对于每种\(de_x+ti\)或者是\(de_x-ti\)分开考虑,把这一类的路径在树上差分(),然后统计某点子树和,可以dfs序+树状数组
换教室
选择某个时间段换会导致这个时间段前后两个相邻时间段的移动代价改变,设\(f_{i,j,0/1}\)表示考虑到第\(i\)个时间段,换了\(j\)次,本次有没有换,转移考虑这两次是换了还是没换,然后讨论一下即可得出转移代价.最短路可以floyed预处理
组合数问题
前缀和
蚯蚓
先对初始序列排序,然后可以发现如果把每次操作后较长的一段放在一个集合,较短的也放在一个集合,那么每次加入集合的一定是集合最小,因为考虑设先加进来是在\(j\)时刻加的,然后它的在\(j\)时刻对应原长为\(x\),当前加进来的在\(j\)时刻原长为\(y(x\ge y)\),那么现在为\(i\)时刻,先加进来的长度为\(\lfloor px\rfloor+(j-i)q\),当前加进来的为\(\lfloor p(y+(j-i)q)\rfloor\),后者显然更小.那么维护三个队列,分别为处决操作队列,较短段的队列,较长段的队列,然后把三个队列队首元素拿出来处决,得到的较长段和较短段分别放进对应队列的队尾
愤怒的小鸟
预处理出选两个点能覆盖的集合,然后转移枚举一个点或者是最小的0位+其他位转移
NOIP2017
小凯的疑惑
ab-a-b
时间复杂度
模拟
逛公园
预处理出\(n\)到其他点的最短路,然后设\(f_{x,k}\)表示在\(x\)点,到\(n\)距离-最短距离为\(k\)的方案,转移枚举出边,然后计算一下多出来的距离部分,记忆化搜索实现.注意搜到在栈中状态就推出
奶酪
小学数学+并查集
宝藏
状压,先预处理\(g_{i,j}\)表示\(i\)集合要和\(j\)集合联通的最小代价,可以先预处理每个点到一个集合的最短边转移,然后设\(f_{i,k}\)表示当前连通集合为\(i\),然后bfs树上有\(k\)层,转移枚举子集,虽然可能有跨层的边,但不会影响最优解
列队
如果只有一行,考虑不把拿到数拿走,并把它加在序列末尾,那么可以树状数组维护哪些位置没被取,然后查的时候就在树状数组上二分,找到最小的位置\(i\)满足前缀和为\(k\),然后拿走这个位置上的数,并且在最末尾加入这个数,再维护树状数组
考虑有多行,对于每行的不是最后一列的询问,只有这一行会对它造成影响,那么每一行对询问离线,然后按顺序处理询问,可以知道每个询问拿的是哪个位置,如果是前\(m-1\)位可以直接计算,否则在这一行后续的\(\text{vector}\)之中.然后维护最后一列的树状数组和\(\text{vector}\),以及每一行后面加进来的\(\text{vector}\),按顺序操作一波,每次在最后一列中取出对应位置上的数放在某一行\(\text{vector}\)末尾/把这次取出来的数放在最后一列\(\text{vector}\)末尾即可
NOIP2018
铺设道路
同积木大赛
货币系统
可以发现把能被其他集合中数表示出来的数删掉就可以得到最小的集合,完全背包即可
赛道修建
二分最终答案,然后看能不能选出\(m\)条长度\(\ge mid\)的路径,dfs一遍,然后得到一堆子树上来的链,然后先把本来\(\ge mid\)的先加到答案里,再把剩下的两两匹配,具体是从小到大枚举没匹配的,然后选择最小的长度加起来满足要求的匹配,剩下一些不能匹配的,取最大值作为当前点伸上去的链,具体实现可以multiset/链表双指针
旅行
树的情况,dfs时每次选能走的最小的儿子走即可
基环树的情况,枚举断掉一条边,就变成树的情况的,选字典序最小的
填数游戏
保卫王国
大概要处理出\(f_{x,0/1}\)表示\(x\)选/不选,以\(x\)为根子树最小花费,\(g_{x,0/1}\)表示\(x\)选/不选,\(x\)子树外的最小花费,\(h_{x,j,0/1,0/1}\)表示\(x\)往上连续\(2^j\)个点的链,两端分别为选/不选,链上点以及旁边分支里的点的最小花费,转移分类讨论 其实是不想写了