2024.11.15 NOIP 模拟赛 题解
T1 数字(number)gym 105257 G. Disappearing Number
题意
求 \(0\sim n\) 中十进制表示下不含 \(a_{1\sim m}\;(0\le a_i\le 9)\) 的数字数量,\(n\le10^{18}\),多测 \(t\le10^5\)
分析
设 \(n\) 的十进制表示为 \(v_{1\sim l}\),其中 \(a_1\) 为最低位
令 \(C=\{x\mid x\notin \{a\},0\le x\le 9\}\)
先特判 \(0\) 是否合法
剩余合法数字可以分为两类类:
- 数位小于 \(l\) 的,这部分有 \(\sum_{i=1}^{l-1}\sum_{j\ne0,j\in C}|C|^{i-1}\),其中前一个 \(\sum\) 枚举数位,后一个枚举最高位
- 数位等于 \(l\) 的,令 \(j\) 为最小的数满足 \(v_j\notin C\)(若不存在则为 \(0\)),则答案为 \(\sum_{i=j}^{l+1}\left(\sum_{j=0}^{v_{i-1}}[j\in C]|C|^{i-2}\right)\),其中前一个 \(\sum\) 枚举和 \(n\) 的最大公共前缀为 \(v_{l\sim i}\),后一个枚举第一位不相同的(若 \(i=1\) 则令括号中式子为 \(1\))
时间复杂度 \(O(tw\log_{10}V)\),其中 \(w=10\) 为字符集大小
实现精细可以做到 \(O(t\log_{10}V)\)
T2 加训(train)CF733E Sleep in Class
题意
给定一个字符序列 \(a_{1\sim n}\;(a_i\in\{'L','R','O'\})\),初始位于 \(p\),若 \(a_p='O'\) 则直接结束;若 \(a_p='L'\) 则令 \(a_p\leftarrow 'R',p\leftarrow p-1\);若 \(a_p='R'\) 则令 \(a_p\leftarrow 'L',p\leftarrow p+1\)。对于每个 \(1\le p\le n\),求出结束前移动的距离(\(p\pm1\) 为移动一单位距离)。\(n\le5\times10^5\)
分析
将 \(a\) 按 \('O'\) 分割开
显然 \('O'\) 的位置答案是 \(0\)
以下的 \(a_{1\sim n}\) 为分割后的一段(\(a_i\ne 'O'\),这也是原题的问题,只不过将 \('L'\) 和 \('R'\) 换为 \('D'\) 和 \('U'\))
对于一个位置 \(p\),设其左侧的 \('R'\) 分别位于 \(L_{1\sim x}\)(\(L_i>L_{i+1}\)),其右侧的 \('L'\) 分别位于 \(R_{1\sim y}\)(\(R_i<R_{i+1}\))
RLLLLRLRLLLLRRRLRLRRLRR
^ ^ ^ ^ ^ ^ ^
L3 L2 L1 p R1 R2 R3
若 \(a_p='L'\),则先回从 \(p\) 移到 \(L_1\),并将 \(a_{(L_1,p]}\) 范围都设为 \('R'\),将 \(a_{L_1}\) 设为 \('L'\)。然后从 \(L_1\) 向右移到 \(R_1\),将 \((L_1,R_1)\) 设为 \('L'\),将 \(a_{R_1}\) 设为 \('R'\)。······。若 \(x\le y\),则最后会从 \(R_{x}\) 向左一直移出范围;否则从 \(L_{y+1}\) 向右移出范围
前者的答案为 \((p-L_1)+(R1-L_1)+(R_1-L_2)+\cdots+(R_x-L_x)+(R_x-0)=p-2\sum_{i=1}^xL_i+2\sum_{i=1}^xR_i\),后者答案为 \((p-L_1)+(R_1-L_1)+(R_1-L_2)+\cdots+(n+1-L_{y+1})=p-2\sum_{i=1}^{x+1}L_i+2\sum_{i=1}^xR_i+n+1\)
显然可以在扫描的同时 \(O(1)\) 维护
同理可以得到 \(a_p='R'\) 时的结果
总时间复杂度 \(O(n)\)
T3 排序(sort)P8996 [CEOI2022] Abracadabra \(\quad\) LOJ #3813. 「CEOI2022」Abracadabra
题意
给定 \(a^0_{1\sim n}\),\(a^i=f(a^{i-1})\),\(q\) 次询问 \(t,i\),查询 \(a^t_i\),\(a^0\) 为一个排列,\(n\le2\times10^5,q\le10^6,t\le10^9,2|n\),其中 \(f\) 变换如下:
f(a):
newa=array[n]
cnt=0
j=n/2+1
for i from 1 to n/2:
while j<=n and a[j]<a[i]:
newa[++cnt]=a[j++]
newa[++cnt]=a[i]
while j<=n:
newa[++cnt]=a[j++]
return newa
即归并排序省略了向下递归
分析
令 \(nx_i\) 为 \(i\) 之后第一个大于 \(a_i\) 的位置(不存在为 \(n+1\))
将序列按 \([1,nx_i),[nx_i,nx_{nx_i}),\cdots\) 分段
显然段的第一个值组成的序列递增
\(f\) 变换相当于将横跨 \([1,n/2]\) 和 \([n/2+1,n]\) 两个区间的段从 \(n/2\) 之后的位置断开,前面的为一段,后面部分再割成若干段,然后将所有段按第一个元素排序,并拼成一个长度为 \(n\) 的序列。若不存在横跨的段,则序列不变
显然 \(f^{n-1}(a)=f^n(a)\)(因为序列至多被割开 \(n-1\) 次),因此令询问的 \(t\) 对 \(n\) 取 \(\min\)
对于没有被割开的段,显然变换之后位置不变
因此建立树状数组,位置 \(i\) 维护起始值为 \(i\) 的段的长度
因为段起始值构成序列有序,因此可以树状数组上二分求出 \(n/2+1\) 位置所属的段的起始值(即为树状数组中 \(n/2+1\) 前第一个有值的下标)和该位置到所在段起始点的距离(就是 \(n/2+1\) 位置到所求下标的距离)
若没有割开这段,则之后序列都不会变化
否则先跟新前面部分的长度,然后根据 \(nx\) 求出 \(n/2+1\) 开始的段的长度并插入树状数组
由于询问的 \(t\) 无序,因此需要将所有的询问离线下来,放到时间轴上,当处理到那个时间断面时回答相关询问;否则需要可持久化树状数组,不知道能不能做,就算可以,时间空间应该都比较卡
时间复杂度 \(O((n+q)\log n)\)
T4 改造(modification)QOJ 5013 A. Astral Birth
题意
给定一个长为 \(n\) 的 \(0/1\) 序列,对于每个 \(1\le k\le n\),求出将序列分为 \(k\) 段重排序后的最长不下降子序列的最大值,\(n\le3\times10^5\)
分析
思路 1
基本和 9.7 的 T4 相同
对于一个给定的 \(0/1\) 序列 \(a\),其最长不下降子序列长度为
若令 \(s_i=[a_i=0]-[a_i=1]=\begin{cases}1&a_i=0\\-1&a_i=1\end{cases}\),则 \(a\) 的最长不下降子序列长度为 \(\sum_{j=1}^n[a_j=1]\) 加 \(s\) 的最大前缀和
显然无论如何重排序,\(\sum_{j=1}^n[a_j=1]\) 都不变
因此问题转化为对于每个 \(k\),求出序列 \(s\) 分为 \(k\) 段重排序后的最大前缀和的最大值
显然最优决策是把 \(s\) 割开后,将总和 \(>0\) 的段放到前面,\(<0\) 的放到后面,\(=0\) 的任意,最大前缀和即为所有总和 \(>0\) 的段的和
从 \(s\) 中分离出一段(与其它段不相连),若是前缀或后缀则需要一次分割,其余需要两次
令 \(rs(i)\) 为分割了 \(i\) 次的答案(等于题目中分为 \(i+1\) 段的答案,分为一段,即原序列,需要特判)
枚举 \(L,R\),分别表示是否分离出前缀/后缀
则对于每个 \(k'\),\(rs(2k'-2-L-R)\) 可以对 \(F(L,R,k')\) 取 \(\max\),\(F(L,R,k')\) 表示是否强制选择前后缀的情况下,从 \(s\) 中选出 \(k'\) 段的最大总和
求出一个序列选出 \(k\) 段的最大总和有一个经典技巧,类似反悔贪心,每次选择 \(s\) 的最大子段,加到答案上后将这个区间中每个数变为其相反数
若强制选择前缀,则令 \(0\) 位置为极大值(此题的极大值在 \(1e6\) 级别以上就够了),这样第一次选择时一定会选前缀,注意答案要减去这个极大值。后缀同理
总时间复杂度 \(O(n\log n)\),常数较大
思路 2
对于 \(0/1\) 序列中相同的连续段,可以作为一个整体考虑(显然不会从连续段中间割开)(实际上这点在 思路 \(1\) 的代码中体现了)
这样合并后的段一定 \(0/1\) 相间
则划分为 \(k\) 段的答案就是最长的形如 \(000\cdots000111\cdots111\) 的子序列的长度,满足该子序列来自不超过 \(k\) 个段
这相当于删去若干个段使之合法,最大化剩下的段的总长
显然不会删去连续的两段,否则保留其中一段一定严格更优
同时若删去了其中一段,则其左右相邻段(如果有)会合并为一个新段
设原序列总段数为 \(m\),则可以进一步转化为对于每个 \(k\),求出从所有段中选出若干段删去,满足删去段的总权值为 \(\max(0,m-k)\)(边上的段的权值为 \(1\),中间的为 \(2\)),且选出段两两不相邻,最小化删去段的总长度,对应的答案即为序列总长减去该值
分类讨论边上的两段是否取后,可以转化为反悔贪心,堆维护即可
时间复杂度 \(O(n\log n)\)
思路 3
猜测答案序列是上凸的
可以分治加闵可夫斯基和优化 \(dp\)
时间复杂度 \(O(n\log n)\)
比赛结果
\(100+85+30+0\),预估的是 \(100+100+45+45\),丢了 \(75\) 分

浙公网安备 33010602011771号