(据说是)鏼爷和吴凯路爷爷出的NOIP模拟神题集锦

文章目录

    • (据说是)鏼爷神题
      • Day1
        • T1 回文切割(pal)
        • T2 模(mod)
      • Day2
        • T1 数列(sequence)
        • T2 子集和(subsetsum)
        • T3 棋盘(board)
      • Day3
        • T1 海龟(turtle)
      • Day4
        • T2 欧拉回路(euler)
    • (据说是)吴凯路爷爷神题
      • Day4
        • T2 挣钱(trade)
      • Day5
        • T2 马拉松路径(path)

(据说是)鏼爷神题

Day1

T1 回文切割(pal)

题目大意: 给定一个长为 n n n n n n是偶数)的01串 s s s,我们要反转里面的几位,使得这个01串能由若干偶数长度的回文串连接而成,反转第 i i i位的代价是 w i w_i wi,求最小代价。 n ≤ 2000 n\le 2000 n2000。时限 2 s 2s 2s
做法: 本题需要用到DP。
显然有区间型DP的思路,令 f ( i ) f(i) f(i)为使长为 i i i的前缀满足条件的最小代价,则有:
f ( i ) = min ⁡ { f ( j ) + w ( j + 1 , i ) } f(i)=\min\{f(j)+w(j+1,i)\} f(i)=min{f(j)+w(j+1,i)}
现在的问题就是如何求 w ( l , r ) w(l,r) w(l,r):使 [ l , r ] [l,r] [l,r]一段为回文串的最小代价。
显然偶回文串一定有一个对称轴,在中间的两个数之间。为了让它们回文,那么应该使第 l l l位和第 r r r位相等,第 l + 1 l+1 l+1位和第 r − 1 r-1 r1位相等…那么最小代价就是,如果对应的两个位置当前不等,就要更改其中代价较小的一个。但是,如果我们固定 l l l,枚举 r r r来计算,会发现非常难算,需要 O ( n 3 ) O(n^3) O(n3),但如果改成枚举对称轴计算就会非常简单了,时间复杂度为 O ( n 2 ) O(n^2) O(n2),DP的复杂度也是 O ( n 2 ) O(n^2) O(n2),我们就解决了这一题。

T2 模(mod)

题目大意: 给定一个集合 S S S,内含 n n n个非负整数 a i a_i ai q q q个询问,每次询问给出一个质数 p p p r ( 0 ≤ r < p ) r(0\le rr(0r<p),询问集合 S S S有多少个子集,使得子集内元素的乘积对 p p p取模的结果是 r r r。空集乘积算作 1 1 1 q ≤ 5 , n ≤ 35 , p ≤ 1 0 9 q\le 5,n\le 35,p\le 10^9 q5,n35,p109。时限 4 s 4s 4s
做法: 本题需要用到折半+map+逆元。
由于询问数很小,可以直接当作多组数据处理。如果看到了部分分的话,50分的范围是 n ≤ 18 n\le 18 n18,这显然就可以二进制枚举暴力计算了。而全部的数据范围是 n ≤ 35 n\le 35 n35,这就提示了我们利用折半的思想,把集合拆成两个大小分别为 17 17 17 18 18 18的集合。对于大小为 18 18 18的集合,暴力枚举,在map中存储乘积模 p p p b b b的子集的个数。然后再枚举大小为 17 17 17的集合中的子集,假设这个子集的乘积模 p p p a a a,我们要求出所有满足 a b ≡ r ( m o d    p ) ab\equiv r(\mod p) abr(modp) b b b来累加答案。显然,因为 p p p是质数,所以满足要求的 b b b有且仅有 1 1 1个,直接算出 a a a的逆元再乘 r r r就是了,直接在map中查找即可。于是时间复杂度为 O ( 2 17 ⋅ ( 18 + log ⁡ p ) ) O(2^{17}\cdot (18+\log p)) O(217(18+logp)),可以通过此题。

Day2

T1 数列(sequence)

题目大意: q q q次询问,每次给定 a , b , c , d a,b,c,d a,b,c,d,求以下数列: x 0 = c , x i = a x i − 1 + b x_0=c,x_i=ax_{i-1}+b x0=c,xi=axi1+b中,编号最小的 ≥ d \ge d d的一项的编号,如果不存在输出 − 1 -1 1 q ≤ 5000 , ∣ a ∣ , ∣ b ∣ , ∣ c ∣ , ∣ d ∣ ≤ 1 0 9 q\le 5000,|a|,|b|,|c|,|d|\le 10^9 q5000,a,b,c,d109
做法: 本题需要用到分类讨论。
分类讨论神题。根据正常高中数学推理,得到数列的通项公式: x i = ( c + b a − 1 ) ⋅ a i − b a − 1 ( a ≠ 1 ) x_i=(c+\frac{b}{a-1})\cdot a^i-\frac{b}{a-1}(a\ne 1) xi=(c+a1b)aia1b(a=1),数列有四种可能的增长情况:循环 ( a = 0 , − 1 ) (a=0,-1) (a=0,1),单调增,单调减,或者上下波动( a < − 1 a<-1 a<1)。其他的就直接计算或者二分即可,最麻烦的情况是上下波动,它会呈现奇数项单调增,偶数项单调减(或者相反)的状态,再分类讨论一下二分即可。
(什么毒瘤题啊…完全不想动手写…)

T2 子集和(subsetsum)

题目大意: 给定一个数列 A A A,定义一个数列 A A A是好的,当且仅当对于所有 1 ≤ t ≤ ∑ A i 1\le t\le \sum A_i 1tAi,都存在一个子集 S ⊆ A S\subseteq A SA,使得 t = ∑ S i t=\sum S_i t=Si。问数列 A A A有多少个非空的子数列(不一定连续,所以一共有 2 n − 1 2^n-1 2n1个)是好的。 n , A i ≤ 5000 n,A_i\le 5000 n,Ai5000。时限 2 s 2s 2s
做法: 本题需要用到DP。
考虑贪心地判断一个数列是不是好的。由于我写过FJOI神秘数那题,因此思路很明显:先将数列从小到大排序,如果存在一个 A i A_i Ai,使得 A i > 1 + ∑ j = 1 i − 1 A j A_i> 1+\sum_{j=1}^{i-1}A_j Ai>1+j=1i1Aj,则数列就不是好的,如果不存在这样的 A i A_i Ai,数列就是好的。简单证明一下就是,在到这样的 A i A_i Ai之前,数列都是好的,但是加入 A i A_i Ai后, ( ∑ j = 1 i − 1 A j , A i ) (\sum_{j=1}^{i-1}A_j,A_i) (j=1i1Aj,Ai)这一段开区间就无法表示了,而又因为后面的 A x A_x Ax都比 A i A_i Ai大,因此这一段开区间永远都不可能被表示出来了,所以数列就不是好的,否则它就是好的。
这样一来,我们显然把整个数列从小到大排序,然后令 f ( i , j ) f(i,j) f(i,j)为最大的元素为 A i A_i Ai的元素和为 j j j的好的子数列数目,有:
f ( i , j ) = ∑ k = 1 i − 1 ∑ p + 1 ≥ j f ( k , p ) f(i,j)=\sum_{k=1}^{i-1}\sum_{p+1\ge j}f(k,p) f(i,j)=k=1i1p+1jf(k,p)
显然当 j > A n j>A_n j>An时,具体的 j j j值已经没有意义了(因为它可以被算作任何后面元素的贡献了),这时候直接令 j = A n + 1 j=A_n+1 j=An+1即可。于是用前缀和优化就可以做到 O ( n A n ) O(nA_n) O(nAn)的时间复杂度了。

T3 棋盘(board)

题目大意: 一个 n × m n\times m n×m的棋盘,上面一些格子已经被涂成红色或黑色,现在要给其他的格子涂上红色或黑色,使得任意位于同一行或同一列的三个连续格子不被涂上相同的颜色,求方案数。 n , m ≤ 11 n,m\le 11 n,m11。时限 5 s 5s 5s
做法: 本题需要用到状压DP。
容易想到按行状压DP,但是状态数看上去海量,直接暴做复杂度不可算,因此我们要精简状态。
首先从每一行的状态入手。暴力枚举的话,它会有 2 m 2^m 2m个状态。但鉴于可能有很多状态是不满足连续三格不涂同一颜色的条件的,我们考虑预处理排除掉不满足这个条件的状态。那么在合法状态中,颜色肯定是由长为 1 1 1 2 2 2的连续段形成的,对于一种划分方案,有 2 2 2种涂色方式(第一段涂红色或黑色),而这样的划分方案数是一个经典的问题,答案是斐波那契数列的第 m m m项(前两项为 1 , 2 1,2 1,2时), F 11 = 144 F_{11}=144 F11=144,因此合法的状态数最多有 288 288 288个,比 2 11 = 2048 2^{11}=2048 211=2048少了很多。
又因为每行的状态只有 288 288 288个,而DP时只要考虑上面两行的状态即可判断是否满足条件,因此DP的时间复杂度应该是 O ( n ⋅ 28 8 3 ⋅ m ) O(n\cdot 288^3\cdot m) O(n2883m),算出来有 3 e 9 3e9 3e9这么大,肯定过不了。我们发现问题在于判定条件合法一次是 O ( m ) O(m) O(m)的,能不能更快呢?这时候就要用位运算来强凑了。
首先一个问题是,如何快速判断当前状态在某些位上等于某些数?令当前状态为 x x x,为了提取出固定的位,我们定义一个数 y y y为,如果某一位被限制,这一位就是 1 1 1,否则就是 0 0 0,这样一个数,那么 x   a n d   y x\space and \space y x and y就是 x x x被提取出的那些位的数了。而 z z z定义为如果某一位被限制,这一位就是被限制要成为的数,否则就是 0 0 0,这样一个数,那么当且仅当 x   a n d   y x\space and \space y x and y z z z完全相同时,条件被满足,于是异或一下判断是不是 0 0 0即可。
然后一个问题是,有了连续三行的状态 x , y , z x,y,z x,y,z,如何判断存不存在某一位上全是 0 0 0或者 1 1 1?注意到,如果一位全是 0 0 0 1 1 1,那么这一位上三个数 a n d and and o r or or的结果应该是相同的,否则就不同,因此我们将 x   a n d   y   a n d   z x\space and \space y\space and\space z x and y and z x   o r   y   o r   z x\space or \space y\space or\space z x or y or z异或起来,如果它等于 2 m − 1 2^m-1 2m1(也就是全是 1 1 1),就说明不存在某一位上全是 0 0 0 1 1 1
这样我们就可以 O ( 1 ) O(1) O(1)(计算机中的)判断条件是否满足了,那么优化过的复杂度经过计算是 2.6 e 8 2.6e8 2.6e8 5 s 5s 5s的时间限制下也许能过,有时间写写试试吧…

Day3

T1 海龟(turtle)

题目大意: 在一个网格图上,有一只海龟要顺次经过 n n n个整点,行走的过程是走直线,问行走过程中一共经过多少个整点,重复经过不重复计算。 n , x , y ≤ 1000 n,x,y\le 1000 n,x,y1000
做法: 本题需要用到找规律+模拟。
我们找到一个规律:在两个整点 ( x 1 , y 1 ) , ( x 2 , y 2 ) (x_1,y_1),(x_2,y_2) (x1,y1),(x2,y2)之间的线段上,有 g c d ( ∣ x 1 − x 2 ∣ , ∣ y 1 − y 2 ∣ ) + 1 gcd(|x_1-x_2|,|y_1-y_2|)+1 gcd(x1x2,y1y2)+1个整点,它们的坐标是 ( x 1 + k ⋅ x 2 − x 1 g c d ( ∣ x 1 − x 2 ∣ , ∣ y 1 − y 2 ∣ ) , y 1 + k ⋅ y 2 − y 1 g c d ( ∣ x 1 − x 2 ∣ , ∣ y 1 − y 2 ∣ ) ) (x_1+k\cdot \frac{x_2-x_1}{gcd(|x_1-x_2|,|y_1-y_2|)},y_1+k\cdot \frac{y_2-y_1}{gcd(|x_1-x_2|,|y_1-y_2|)} ) (x1+kgcd(x1x2,y1y2)x2x1,y1+kgcd(x1x2,y1y2)y2y1)。显然每次行走 O ( max ⁡ x ) O(\max x) O(maxx)枚举 k k k对点标记,最后 O ( max ⁡ x ⋅ max ⁡ y ) O(\max x\cdot \max y) O(maxxmaxy)统计即可。

Day4

T2 欧拉回路(euler)

题目大意: n n n个点,点 i i i和点 j j j之间有边当且仅当 ( i − j ) ⋅ ( a i − a j ) > 0 (i-j)\cdot (a_i-a_j)>0 (ij)(aiaj)>0,问连出的图存不存在欧拉回路。 n ≤ 1 0 5 , T ≤ 10 n\le 10^5,T\le 10 n105,T10。时限 2 s 2s 2s
做法: 本题需要用到图论结论+树状数组。
根据图论的结论,一个图存在欧拉回路,当且仅当图中每个点的度数是偶数,并且图连通。求每个点的度数应该简单了,直接求它左边有多少个比它小的,右边有多少个比它大的即可,用树状数组+离散化做到 O ( n log ⁡ n ) O(n\log n) O(nlogn)。关键是如何判连通。
我们先证明一个引理:对于连续排列的三个连通块 A , B , C A,B,C A,B,C,不存在 A , C A,C A,C连通,但 A , B A,B A,B B , C B,C B,C间都没有边的情况。显然,根据 A , C A,C A,C连通,说明 A A A中存在一个元素比 C C C中的某元素小,也就说明 min ⁡ ( A ) < max ⁡ ( C ) \min(A)<\max(C) min(A)<max(C),而 A , B A,B A,B B , C B,C B,C间没有边,可以同样地看成 min ⁡ ( A ) ≥ max ⁡ ( B ) , min ⁡ ( B ) ≥ max ⁡ ( C ) \min(A)\ge \max(B),\min(B)\ge \max(C) min(A)max(B),min(B)max(C),那么 min ⁡ ( A ) ≥ max ⁡ ( C ) \min(A)\ge \max(C) min(A)max(C),所以这两个条件矛盾,因此结论成立。这也就意味着,如果图不连通的话,则必定存在一个分界点 i i i,使得 min ⁡ { a j ∣ j ≤ i } ≥ max ⁡ { a j ∣ j > i } \min\{a_j|j\le i\}\ge \max\{a_j|j>i\} min{ajji}max{ajj>i},直接 O ( n ) O(n) O(n)判定即可,这样我们就解决了这一题。

(据说是)吴凯路爷爷神题

Day4

T2 挣钱(trade)

题目大意: n n n个城市连成树状图,边有长度,现在要倒卖一种物品,这种物品在城市 i i i的价格为 a i a_i ai,选择一个城市购买一件这种物品,再走到另一个城市卖掉,走过一条长度为 x x x的边花费为 x x x,求一次能得到的最大收益。 n ≤ 1 0 5 n\le 10^5 n105
做法: 本题需要用到树形DP。
考虑枚举路径的LCA: v v v,如何计算过这一点的路径的最大价值呢?令 d i s i dis_i disi为点 i i i v v v的距离,那么答案就是子树中 a i − d i s i a_i-dis_i aidisi的最大值加上 − a i − d i s i -a_i-dis_i aidisi的最大值,这些显然都可以用树形DP很自然地维护出来。现在有的同学有疑问了,如果满足这两个最大值的两个点在 v v v的同一个儿子的子树中怎么办呢?当然你想去重也可以去重,但这里因为如果它路径有重,那它肯定没有LCA在另一个点的情况时优,所以我们可以直接不管去重。这样就可以 O ( n ) O(n) O(n)解决这一题了。

Day5

T2 马拉松路径(path)

题目大意: 给定一张带边权无向连通图,给定一个 C C C个点的点集,要从里面选两个不同的点作为起点和终点,求最短路的最小值。 C ≤ n ≤ 1 0 5 , m ≤ 1 0 5 C\le n\le 10^5,m\le 10^5 Cn105,m105。时限 3 s 3s 3s
做法: 本题需要用到最短路+二进制分组。
神仙题。
如果是规定了起点集合和终点集合,直接建超级源点和超级汇点做即可。但是这个题给的 C C C个点都可能作为起点或终点,还限制同一个点不能同时为起点或终点。直接枚举起点,每次做单源最短路,这和暴力没什么区别,我们需要更加优美地枚举所有可能的情况。
注意到两个点不同,一定代表着它们编号的二进制表示中,存在某一位不同。因此我们对每一个二进制位分组,是 0 0 0的分为起点集合,是 1 1 1的分为终点集合,这样就可以保证起点和终点集合不同,而这样 O ( log ⁡ n ) O(\log n) O(logn)次最短路做下来一定会包含所有起点和终点的情况,这样就可以 O ( n log ⁡ 2 n ) O(n\log^2n) O(nlog2n)计算出答案了。

你可能感兴趣的:(总结)