模拟赛题解

红包发红包


打表可以知道答案是 w 2 k \frac w {2^k} 2kw,我们来尝试证明这个答案。

k=1, ∫ 0 w x d x w = w 2 \frac {\int_0^w x {\rm d} x} w=\frac w 2 w0wxdx=2w

k=2, ∫ 0 w x 2 d x w = w 4 \frac {\int_0^w \frac x 2 {\rm d} x} w=\frac w 4 w0w2xdx=4w

那么假设答案是 w 2 k \frac w {2^k} 2kw

我们来归纳这个答案:

首先k=1的情况我们已经说过了。

那么由k-1推到k(k>=2): ∫ 0 w x 2 k − 1 d x w = w 2 k \frac {\int_0^w \frac x {2^{k-1}}{\rm d} x} w=\frac w {2^k} w0w2k1xdx=2kw

归纳完毕,那么我们只需要快速幂算出来答案就好了。

dkw的lcm


这个题的突破点在连乘符号上。

首先, φ \varphi φ是积性函数,我们可以分开质因子讨论,从而避开了直接讨论如何拆开lcm。

具体来说,我们可以枚举质数p以及它的幂次e,计算k个数的lcm在这个质因子p的次数恰好为e的方案数。

然后用快速幂累计答案即可,中间可能有一些细节需要注意。

大概分析一下时间复杂度应该是 O ( n l o g n ) O(nlogn) O(nlogn)级别的,主要是我没有注意实现程序的时间效率,其实可以开更大数据范围来着。

综合来看,本题代码难度中等,思维难度不高,可以较全面地考察选手的综合能力,有着一定的区分度。

出题人相信,这道题可以给拼搏于AK之路上的你,提供一个有力的援助。

能量采集


30分 (t<=50):我们考虑直接模拟能量流动的过程,从第1秒开始,直到第50秒,即可通过本部分分。

60分 (q<=50):我们发现可以将转移写成矩阵,利用矩阵快速幂来优化复杂度,可以做到单次 O ( n 3 l o g 2 t ) O(n^3log_2t) O(n3log2t),总复杂度就是 O ( q n 3 l o g 2 t ) O(qn^3log_2 t) O(qn3log2t),可以通过本部分分。

50分:大概率是你并没有特殊写前30分,被30分里的最后一个点卡掉了,那个点的q开到了50000,n同样开满了50,所以你当然会TLE。

真 · 60分:需要结合模拟和矩阵快速幂两个做法。

80分 (q<=1000):套路做法,我们预处理倍增矩阵,然后每次询问的时候用向量依次去乘每个矩阵,这样就可以减少单次询问的复杂度了,因为向量乘矩阵的复杂度是 O ( n 2 ) O(n^2) O(n2)的,所以总复杂度 O ( n 3 l o g 2 t + q n 2 l o g 2 t ) O(n^3log_2 t+qn^2log_2 t) O(n3log2t+qn2log2t)

伪 · 100分:你只需要一个循环展开就好了,然而我卡了好久也没有成功卡掉循环展开,事实上循环展开会比std快,虽然std循环展开更快就是了2333。

真 · 100分:我们可以发现,在80分做法中,预处理部分非常快,瓶颈其实在询问的部分。于是就有一个非常naive的做法,暂且叫做k倍增吧,具体就是说,我们每次倍增是让幂次乘2,k倍增就是乘k,相当于把询问中的t分解成一个k进制数,然后用初始向量乘以每一位对应的矩阵。

其实也就是说,倍增的时候,对于k进制数的每一位我们都处理出来这一位为分别为1~k-1时的转移矩阵,那么我们的预处理复杂度就是 O ( n 3 k l o g k t ) O(n^3klog_k t) O(n3klogkt),单次询问复杂度则是 O ( n 2 l o g k t ) O(n^2log_k t) O(n2logkt),那么总复杂度就是 O ( n 3 k l o g k t + q n 2 l o g k t ) O(n^3klog_k t+qn^2log_k t) O(n3klogkt+qn2logkt)

接下来的问题就是k取什么值最优。直觉上来看,应该让两边相等,解出来了k=q/n,但是实际上这并不是最优复杂度,具体可能需要求导,但是有个投机取巧的做法,我们可以爆算复杂度呀,经过实际计算,当q=50000,n=50的时候,k取200~300时会达到最优的时间,实测的结果是k取230基本上达到了最快,然而还是不够我卡掉循环展开2333

综合来看,本题代码难度中等,思维难度中等,可以较全面地考察选手的综合能力,有着较高的区分度。

出题人相信,这道题可以给拼搏于AK之路上的你,提供一个有力的援助。

归程


子任务1:爆搜选钥匙方案即可。

我们简化一下题意:给定n个k位v+1进制数,有m个询问,每次询问给定一个目标数,求选出不超过c个数使得这c个数做不进位加法的结果为目标数,两个方案不同当且仅当所用数的个数不同,或者某次用的数不同。

子任务2:我们发现当v=1,也就是二进制下时,不进位加法就代表着异或,那么我们可以设计dp状态:dp(i,j)代表着用了i个数,当前异或和为j,的方案数。转移直接枚举这一位填什么数,即可做到 O ( m a x c ⋅ 2 2 k ) O(maxc\cdot 2^{2k}) O(maxc22k) 的复杂度了,但是这并不能通过该子任务。我们发现,这个dp可以使用fwt优化,就可以做到 O ( m a x c ⋅ 2 k k ) O(maxc\cdot 2^k k) O(maxc2kk) 的复杂度了。

如果不是二进制呢?我们还能继续使用fwt吗?

我们考虑fwt的本质。比如给定两个数列A,B,求A和B的集合对称差卷积,那么fwt的本质就是构造一个变换fwt使得fwt(A)·fwt(B)=fwt(A·B),那么它本质也就是个高维fft罢了。

那么我们只需要沿用fft中的复数单位根,就可以满足变换的性质了。

证明我这里省略了,你们可以自己手推一下fwt,就会十分清楚地明白fwt的变换本质上相当于乘了一个矩阵,逆变换就相当于乘了逆矩阵,那么这一堆变换系数只需要满足fwt(A)·fwt(B)=fwt(A·B)且系数矩阵存在逆矩阵即可。易证复数单位根所组成的若干组解是满足条件且数量足够的。

那么就可以沿用fwt优化dp了,这里就需要自己实现v+1进制fwt了。

最终可以做到 O ( m a x c ⋅ ( v + 1 ) k + 2 ) O(maxc \cdot (v+1)^{k+2}) O(maxc(v+1)k+2) ,其中 ( v + 1 ) k + 2 (v+1)^{k+2} (v+1)k+2 其实是 ( v + 1 ) k ⋅ ( v + 1 ) 2 (v+1)^k \cdot (v+1)^2 (v+1)k(v+1)2 前一部分代表状态数即数列长度,后一部分代表做一次变换所需要的复杂度。这个复杂度足够通过子任务1~5了。

关于子任务3,4的特殊解法:我们只需要分别找两三个3进制NTT模数和4进制NTT模数,最后用CRT合并就可以直接做到3,4进制fwt了。

子任务6:我们的复杂度中始终乘了一个maxc,现在我们试图降低这部分的复杂度。我们考虑如果初始状态叫做 I I I ,变换所需要乘的卷积叫做 A A A 的话,那么答案就是 I A + I A 2 + I A 3 + . . . + I A c IA+IA^2+IA^3+...+IA^c IA+IA2+IA3+...+IAc

我们将 I I I 提出来,剩下的是一个类似等比数列的东西 A + A 2 + . . . + A c A+A^2+...+A^c A+A2+...+Ac

我们发现寻常的等比数列求和方法对它并不奏效,所以我们考虑一个较通用的求和方式——分治法。

我们递归求 B n = A + A 2 + A 3 + . . . + A n B_n=A+A^2+A^3+...+A^n Bn=A+A2+A3+...+An

如果n是偶数,那么答案就为 B n / 2 + A n / 2 B n / 2 B_{n/2}+A_{n/2}B_{n/2} Bn/2+An/2Bn/2

如果n是奇数,那么答案就是 A + A ( B n / 2 + A n / 2 B n / 2 ) A+A(B_{n/2}+A_{n/2}B_{n/2}) A+A(Bn/2+An/2Bn/2)

那么我们就可以做到单次询问 O ( ( v + 1 ) k + 2 l o g c ) O((v+1)^{k+2}logc) O((v+1)k+2logc) 了,总复杂度 O ( q ( v + 1 ) k + 2 l o g c ) O(q(v+1)^{k+2}logc) O(q(v+1)k+2logc) ,再加上前面子任务的特判,也就是对c<=100的部分预处理,就可以AC了。

这题的灵感在于我做一道四进制fwt的题的时候,发现fwt可以推广到k进制上,就出出来了这个题。

综合来看,本题代码难度较高,思维难度较高,可以较全面地考察选手的综合能力。

出题人相信,这道题可以给拼搏于AK之路上的你,提供一个有力的援助。

你可能感兴趣的:(模拟赛题解)