历年NOI真题选做

没啥水平,大家将就着看,帮忙催更哦~

[NOI2013] 向量内积

题意

观察发现暴力很足,可以直接 \(O(n^2d)\)

继续观察数据范围,发现 \(K=2\)\(K=3\)\(K=2\) 可以用 \(bitset\) 无脑草过去,复杂度 \(O(\frac{n^2d}{w})\)

\(K=3\) 就魔改一下 \(bitset\)。考虑 \(\mod 3=0\) 的设为 \(0\) 其余为 \(1\) ,剩下的应该是 \(1\times 2,2\times 1,1\times 1,2 \times 2 ,\mod 3=2,2,1,1\),就相当于少算了 \(1\times 2,2\times 1\) ,于是按照 \(\mod 3==2\) 来补齐没算的。

直接枚举可能不太行,考虑随机打乱排列大概有 95 ,剩下的 5 分 reverse 一下排列就能得到。稍微判断一下(但是在考场上我可能只能搞到95)。

[NOI2016] 区间

题意

类似于今年省选 A 卷 D1T1,就是不断往后加到合法,前面每次往后退一个。

[NOI2013] 快餐店

题意

考虑一棵树,一定是最长链某个位置劈开。

现在是个基环树,考虑最长路径不经过环,那就把环劈了,找环上某个点,使得离这个点最远的子树距离最小。

这个可以把环拉开然后根据子树距离排一下,统计前后缀 max 计算答案。

但是可能最优位置不在环上,那我们还得把某两个点在环上的距离加上,就是计算的时候我们要算链长,环上距离长,子树深度。

统计的时候就是枚举环上某一个点 \(i\),更新 \(\min(\max(\) \(i\) 子树最大深度 \(+i\) 之前的链长 \(+i\) 之后的链长,\(\max(\) \(i\) 前面两个点 \(u,v\) 的最大深度 \(+(u,v)\) 在环上的距离,\(i\) 后面两个点 \(u,v\) 的最大深度 \(+(u,v)\) 在环上的距离 \()))\)

细节有点多。

参考

[NOI2015] 寿司晚宴

题意

怀疑我打过的这种套路的模拟赛都是从这题衍生来的。(你谷月赛,校内 NOIp 模拟赛)

考虑两个数不互质说明它们有公共的质因数,考虑 \(n \leq 30\) 一共只有 \(10\) 个质因数可选,于是可以设 \(f[s1][s2]\) 表示第一个数选的因数集合是 \(s1\) ,第二个数选的因数集合是 \(s2\) 。那么 \(f[s1|i][s2]+=f[s1][s2](i\&s2==0),f[s1][s2|i]+=f[s1][s2] (i\&s1==0)\) ,由于 dp 的时候数组值会改变所以要滚一下不能直接修改原数组(两个数组互相转移)。

然后发现可以按照 \(\leq \sqrt{n},\gt \sqrt{n}\) 来分类质因数,因为 \(\gt \sqrt{n}\) 的质因数最多只有一个。

那么就是 \(\leq 22\) 的质因数 (2,3,5,7,11,13,17,19) 和 \(\gt 22\) 的质因数。我们可以把每个数预处理一下,算出来它最大的质因数是多少,排个序,然后状压 dp

\(f[i][j][k][0/1/2]\) 表示前 \(i\) 个质因数中,第一个数选的小质数集合为 \(j\) ,第二个数选的小质数集合为 \(k\) ,两个人都没选 / 第 \(1/2\) 个人选了 第 \(i\) 个质因数的方案数。

转移:

\[f[i][j][k][0]+=f[i-1][j][k|s][0](j\&s==0)\\ f[i][j][k][1]+=f[i-1][j|s][k][1](k\&s==0)\\ f[i][j][k][2]=f[i][j][k][0]+f[i][j][k][1]-f[i-1][j][k][2] \]

发现 dp 的时候可以类似 \(01\) 背包那样从后往前枚举,这样可以省掉一维。

想的时候有点细节,写起来很舒适。

[NOI2018] 冒泡排序

题意

发现 \(O(n^2)\)\(80pts\) 的高分,就先去想了 \(O(n^2)\) 做法。

首先写一个暴力,打表长度为 \(n\)\(i\) 开头的合法排列个数:

1 
1 1 
2 2 1 
5 5 3 1 
14 14 9 4 1 
42 42 28 14 5 1 
132 132 90 48 20 6 1 

诶,觉得第一项好眼熟啊……萌神在我右边看了一眼,说:“不会吧不会吧不会真有人不会卡特兰数吧?”

卡特兰数是 \(\frac{\binom{2n}{n}}{n+1}\) ,于是我有了大胆猜想,把每一项都 \(\times (n+1)\) ,看到是这个东西:

1 
2 2 
6 6 3 
20 20 12 4 
70 70 45 20 5 
252 252 168 84 30 6 
924 924 630 336 140 42 7 
3432 3432 2376 1320 600 216 56 8 
12870 12870 9009 5148 2475 990 315 72 9 

本来卡特兰数就有组合数,加上 \(20,45,252\) 这种具有提示性的东西,我就向组合数上想了……

大概过了半个多小时摸出来(结果萌神说可以用网格行走直接推)是:

\[\frac{\binom{n+i}{i} \times (n-i+1)}{n+1} \]

嗯,不用写 \(O(n^2)\) 了,这个柿子可以预处理组合数 \(O(1)\) 计算。

考虑计算大于某排列字典序的排列个数,可以逐位计算大于它的排列个数,就是以大于它的数开头的排列个数,每一位依次算下去。

所以这个也是一样的道理,但是要扣掉一些不合法的,就是往后走的时候要把当前这个数减去比他小的数的个数,然后到某个位置不合法了就跳出,细节很多。

用网格行走推:

首先有个结论:最长下降子序列的长度不能超过 2。

证明可以看这个 ,感觉有点麻烦(我考场上肯定证不出来啊!)。

然后设 \(dp[i][j]=\) 选了 \(i\) 个数放入序列最大值为 \(j\) 的方案数, \(j\) 可以转移到比 \(j\) 大的,由于最长下降子序列长度不能超过 2 ,所以只能向未选的最小值选,那么 \(f[i][j] \rightarrow f[i+1][j+k] (j+k\leq n,k \geq 0)\) ,我们把 \((i,j)\) 抽象成一个点,实质上就是求 \((0,0) \rightarrow (n,n)\) 且不跨过 \(y=x\) 而且在它上面的,只能向上向右走的方案数(实际上这就是卡特兰数)。有了字典序的限制,可以考虑按照数位 dp 的方式一步步找限制,到某个地方超过限制了就跳出。

参考

[NOI2019] 弹跳

题意

\(1 \sim 8 :\) 暴力连边 \(+\) dij

\(9 \sim 13 :\) 离线预处理 \(+\) 暴力连边 \(+\) dij

\(14 \sim 18 :\) 线段树优化建图 \(+\) dij

随手写写拼拼就好了,所以我在考场大概只有暴力分……

考虑满分做法就是把一维的线段树优化建图搞到二维上去,直接二维线段树优化建图会被卡空间(卡得特别严重,吐了,不知道出题人什么心态啊),然后膜了膜题解(参考

发现空间限制的瓶颈在于边比较多,由于 dij 的时候每个点都会只会更新一遍,考虑不直接连边,先把里层的建出来,然后对于外层的可以按照最短路的扩展方式,每次加边的时候就更新这一段的最短路,并且把更新过的区间加入队列中。这样就可以避免卡空间了,最大的点用了 123 MB 左右。(不带注释一共 4.73K,168行……)

[NOI2018] 归程

题意

\(1\sim 4,6\sim 9,15,16:\) 有一个很显然的暴力,就是先预处理所有点到终点的最短路(建反图跑一遍),然后每次根据水位线建出车子可以走的图,做一遍 dij ,再枚举从哪个点下车是可行的而且路径最短,更新答案。时间复杂度 \(O(nQ)\) ,期望得分 \(50\)

\(5:\) 海拔只有一种,要么都能选要么都不能选,可以直接判断能不能走,\(ans=0\)\(dist[n]\) ,期望得分 \(5\)

\(10,11:\) 考虑一条链的情况:存在某条边有积水,在这里必须下车,每次只要找到 \(1\sim n\) 的路径上第一条有积水的边就可以了,实际上可以预处理这条路径的前缀 min,由于这个是单调不增的可以二分。由于链的包和暴力重合,所以链应该是对树有提示的。那么考虑树上某个点,我们可以走到这个点,然后从这个点下车走到终点,还是可以预处理终点到每个点的最短路,由于每个点到出发点的路径是唯一的,所以可以预处理路径最小值,每次找 \(\min \geq\) 水平面的且距离最短的,可以根据路径上的min排序之后做后缀 max解决。期望得分 \(10\)

\(12,13,14:\) 不强制在线可以把水位线排序,由于每次只会加边,所以可以先预处理最短路,每加一条边更新一下答案,就是加进来之后和 \(1\) 相连的连通块里的路径长度最小值。期望得分 \(15\)

所以比较正常的暴力大概有 \(80\) 。(写正解但是用了 spfa 的似乎没这个分……)

考虑正解:kruskal 重构树。树上某条 \(i \rightarrow j\) 的边表示图上 \(i\rightarrow j\) 的路径上边的最小值,这样根到任意一个点路径上的边权是递增的。由于根到 \(fa[i]\) 的距离比根到 \(i\) 的距离大,所以建树的时候用并查集维护,对于每条边 \((u,v,w)\) ,如果 \(v\) 到根的距离比 \(u\) 大说明 \(v\)\(u\) 的祖先,那么就连一条 \(v \rightarrow u\) 的边。这棵树相当于并查集不路径压缩的状态,可以直接倍增跳,由于边权是降序的,所以跳到最后就是海拔高度。

[NOI2017] 游戏

题意

上来看到这种东西: 若在第 \(i\) 场使用型号为 \(h_i\) 的车子,则第 \(j\) 场游戏要使用型号为 \(h_j\) 的车子。

这就是一个选了 \(i\) 就要选 \(j\) 的限制。

发现场地有 x a b c 四种,特别是这个 x 很麻烦,但看到有一半 \(d=0\) 的,所以先考虑 \(d=0\)

现在每种场地只能用 2 种车子,令 \(i\) 表示用第一种车,\(i'\) 表示用第二种车,分类讨论一下:

  • \(i\) 号场地不能用 \(h_i\) : 不用管这个条件

  • \(i\) 号场地可以用 \(h_i\)\(j\) 号场地不能用 \(h_j\) : 连边 \(i \rightarrow i'\) 表示如果用了一定无解

  • \(i\) 号场地可以用 \(h_i\)\(j\) 号场地可以用 \(h_j\) : 连边 \(i \rightarrow j , j' \rightarrow i'\) 表示如果用了 \(i\) 一定要用 \(j\) ,如果没用 \(j\) 一定不用 \(i\)

然后缩点,dfs,找 scc ,如果 \(i\)\(i'\) 在同一个 scc 肯定无解,否则把缩点后的图拓扑排序,如果 \(i\) 的拓扑序在 \(i'\) 之后,说明 \(i\) 用第一种可用的,否则用第二种。这样可以获得 \(45\) 分的好成绩。

再考虑 x ,发现并不会 3-SAT

我们发现 x 非常少,只有 \(8\) 个。我们可以暴力枚举每个 x 适合哪两种赛车,这样是 \(3^d\) ,还有 \(20\) 分拿不到。

注意到我们枚举适合的赛车 AB AC BC,就是 x=a / x=b / x=c ,其实我们已经尝试 “这个位置能否选 A B C” ,所以可以任意去掉一种情况不要再尝试了。

这时候时间复杂度被降低到 \(O(2^d(n+m))\) ,可以通过本题。

数据太垃圾了,只有 #9 #10 有一丢丢强度,我清空写错了都有 \(90pts\) ……

[NOI2012] 骑行川藏

题意

一开始以为全程一个速度,把式子展开一看觉得可能无解,重新看题发现每段速度不一样……

用数学语言描述这个题:

\[\sum_{i=1}^n s_ik_i(v_i-v_i')^2 = E\\ ans=\min\{\sum_{i=1}^n \frac{s_i}{v_i}\} \]

观察部分分发现会 \(n \leq 2\) 可以获得 \(40pts\)\(n=1\) 的时候直接做,\(n=2\) 可以三分其中一个算另外一个。(我也不知道我哪里写挂了只有 \(35\)

考虑每一段都可以花费一些能量来减少一些时间,也就是每一段都有一个性价比。根据木桶效应,最优时应该每一段的性价比一样。我们可以二分这个性价比求解。

那么这个性价比怎么表示呢?当然是 \(\frac{\Delta t}{\Delta E}\) 这样的形式。这个就是导数的基本思想了。

为了方便我们把 \(v\) 作为变量,那么 \(F(v)\) 可以用 \(\frac{\frac{dt}{dv}}{\frac{dt}{dE}}\) 表示。

\[t=\frac{s}{v}\\ t'=-\frac{s}{v^2}\\ E=sk(v-v')^2\\ E'=2sk(v-v') \]

然后可以二分导数,然后二分出导数为 \(mid\) 时的最优答案。

在洛谷上一直 \(85\) 显示我输出 -nan,卡了一个小时,去 loj 下数据发现没错,结果交到 loj 上过了??垃圾洛谷!

[NOI2017] 整数

题意

暴力就是按题意来,直接模拟。

但是发现修改的位置连续性没有那么强,是一段一段修改的,可以用 set 维护一下最近的要改的位置,每次修改的复杂度就是 \(\log\) 的。

[NOI2019] 机器人

题意

最基础的暴力有 20。

考虑稍微有点技术含量的,\(B_i \leq 10^4\) :设 \(F[l][r][x]=\) 现在的区间是 \([L,R]\) ,这个区间最高的柱子是 \(x\) 的方案数。我们枚举最大值所在的点 \(K\) ,那么 \(F[l][r][x]=\sum_K \sum_{y\leq x} F[l][K-1][y] \times F[K+1][r][y-1]\)

发现 \(300 \times 300 \times 10^4\) 会爆空间,但是仔细思考会发现很多状态是可以剪枝的,所以把每个区间 \([l,r]\) 编上号,冗余状态剪掉,只管有值的状态,这样可以获得 \(50pts\)

看到 \(A_i=1,B_i=10^9\) ,觉得应该有某种规律,应该是一个可以被插出来的多项式,那么正解也往多项式上想。

我们发现当 \(l=r\) 时,dp 状态是一个多项式 \(x^0\) ,前缀和是 \(x^1\) ,拓展合并后的多项式,发现 \([l,r]\) 的 dp 前缀和是 \(r-l+1\) 次多项式,然后插值。

考虑 APIO2016 划艇 的套路,把每个区间 \([a_i,b_i)\) 离散化下来,拆开,这样我们只需要 dp 每一段区间 \([L,L+n)\) ,对每个 dp 状态的前缀和进行插值。同时求出其在 \(L_{i+1}-1\) 处的值,再做下一段即可。

因为下标连续所以可以线性插值。时间复杂度 \(O(n^2m)\)

[NOI2014] 购票

题意

考虑 dp ,\(f_i\) 表示从 \(i\) 出发,所需要的最小购票费用。

\[f_i=\min_{x \in anc_i,dis_i-dis_x \leq l_i }\{ f_x + (dis_i-dis_x)\times p_i + q_i\} \]

展开一下这个式子,移项:

\[f_i=\min_{x \in anc_i,dis_i-dis_x \leq l_i }\{ f_x -dis_x \times p_i\} + dis_i \times p_i + q_i \]

考虑两个点 \(u,v\) ,假设 \(dis_u<dis_v\) ,那么 \(u\)\(v\) 更优:

\[f_u-dis_u \times p_i < f_v -dis_v \times p_i\\ f_u-f_v < (dis_u-dis_v) \times p_i\\ \frac{f_u-f_v}{dis_u-dis_v} > p_i\\ \]

如果这个不是在树上而是在序列上,可以随便维护一个单调队列就没了。

[NOI2007] 生成树计数

题意

posted @ 2021-04-26 08:42  kylin_xy  阅读(782)  评论(1编辑  收藏  举报