2019各省省选试题选做
2019.05.09
把拖了几天的SDOI Day2更了。姑且算是完结撒花?
省份 | Day1T1 | Day1T2 | Day1T3 | Day2T1 | Day2T2 | Day2T3 |
---|---|---|---|---|---|---|
ZJOI | \(\surd\) | \(\surd\) | \(\surd\) | \(\surd\) | \(\surd\) | \(\surd\) |
HNOI | \(\surd\) | \(\surd\) | \(\surd\) | \(\surd\) | \(\surd\) | \(\surd\) |
十二省 | \(\surd\) | \(\surd\) | \(\surd\) | \(\surd\) | \(\surd\) | \(\surd\) |
GX/GZOI | \(\surd\) | \(\surd\) | \(\surd\) | \(\surd\) | \(\surd\) | \(\surd\) |
BJOI | \(\surd\) | \(\surd\) | \(\surd\) | \(\surd\) | \(\surd\) | |
SNOI | \(\surd\) | \(\surd\) | \(\surd\) | \(\surd\) | ||
JSOI | \(\surd\) | \(\surd\) | \(\surd\) | \(N/A\) | \(N/A\) | \(N/A\) |
TJOI | \(\surd\) | \(\surd\) | \(\surd\) | \(\surd\) | \(\surd\) | \(\surd\) |
SDOI | \(\surd\) | \(\surd\) | \(\surd\) | \(\surd\) | \(\surd\) | \(\surd\) |
ZJOI
Day1T1 麻将
先考虑一个这样的问题:给定一副麻将问其是否存在一个子集能胡。两种牌型中七对子很好处理,只需要记有多少种数值出现了大于等于\(2\)次就行了。
考虑用\(dp\)去判定是否能按第一种牌型胡。\(f_{i,0/1,j,k}\)表示从小往大考虑了\(1...i\)的面值,前面是否选了对子,选了\(j\)个\(i-1,i,i+1\)顺子,\(k\)个\(i,i+1,i+2\)顺子,最多能凑出的面子数(由于\(i+1\)尚未确定,因而\(j,k\)并不会被计入面子数)。转移时根据\(i+1\)的数量,枚举\(i+1,i+2,i+3\)顺子的数量,剩下的\(i+1\)组成刻子。
再考虑原题目中的权值期望怎么转化。显然这个期望可以拆成“在手上有\(i(i\ge13)\)张牌时检查是否胡牌,若不胡则贡献\(+1\)”,因此我们考虑求出有\(i\)张牌时仍不胡的方案数,乘上\((4n-i)!\)后相加即可得到总答案。
回到原问题。在原问题中我们仍考虑按面值从小到大加入麻将牌,并将上述判定胡牌的\(dp\)数组作为状态压进当前\(dp\)中。经搜索发现本质不同的状态只有\(S=3956\)种,本质不同的不胡状态只有\(S_0=2091\)种,因而可以设\(dp_{i,j,k}\)表示考虑\(1...i\)的面值,当前状态为\(j\),选了\(k\)张牌的方案数,转移只要枚举\(i+1\)面值选多少张,方案数乘个组合数即可。总复杂度为\(O(n^2S_0)\)。
code
Day1T2 线段树
可以发现操作的意义等价于,每次以\(\frac 12\)的概率进行一次区间覆盖操作,求线段树上有标记节点的期望个数。根据期望的线性性,只需要求出每个节点有标记的概率\(f_i\)再求和即可。
为了方便的维护这个概率,我们需要额外对线段树上每个点维护该点到根的路径上有标记的概率\(g_i\)。每次修改都会有\(O(\log n)\)个节点的\(f_i\)值变成\(\frac{f_i}{2}\)或\(\frac{f_i+1}{2}\)或\(\frac{f_i+g_i}{2}\)中的一种(请根据实际含义自行理解),而同时也会有\(O(\log n)\)棵线段树子树内的\(g_i\)值变成\(\frac{g_i+1}{2}\)。
在具体实现中,可以维护\(g_i'=1-g_i\),这样对子树内\(g_i'\)的修改就变成了\(g_i'\gets \frac{g_i'}{2}\),直接打区间乘法标记(或者直接记区间要除几次\(2\))即可。
code
Day1T3 Minimax搜索
考虑对每个\(R\)求出\(ans_R\)表示有多少个叶子集合满足权值\(\le R\),差分即可得到答案。设树上共有\(k\)个叶子节点,易知\(ans_n=2^k-1\)。
由于我们只需要改变\(w\)的值,而变成的值的可行域显然是连续的,所以我们只需要尝试着将这个值改为\(w+1\)或\(w-1\)即可。
如果可修改集合包含\(w\)那么其权值一定为\(1\)(只要把\(w\)改掉就万事大吉了),因此\(ans_1=2^{k-1}\)。
否则,如果想要把权值变成\(w+1\),那么大于\(w\)的点的权值显然不会被修改,而小于\(w\)的点的权值会被尽量改成\(w+1\)(如果修改代价不超过\(R\)的话)。把权值变成\(w-1\)的过程同理。可以发现两类修改互不影响,所以我们只要分别求出两类操作下\(w\)没有被改变的方案数,直接相乘得到的就是\(w\)没有被改变的方案数。
设\(f_i\)表示\(i\)点权值\(\le w\)的概率(设概率而非方案数可以方便转移),这样奇数深度的转移为\(f_u=\prod f_v\),偶数层的转移为\(f_u=1-\prod(1-f_v)\)。同理,设\(g_i\)表示\(i\)点权值\(< w\)的概率,转移与\(f\)的转移完全一致。注意在这里\(f_i\)只考虑所有\(
由此在\(R\)确定的情况下我们可以通过一遍树形\(dp\)求出\(ans_R=2^{k-1}(1-f_1(1-g_1))+2^{k-1}\)。这样我们就得到了一个\(O(n(R-L+1))\)的做法,可以获得\(70\)分。
满分做法其实很显然。\(R\)从\(2\)向\(n-1\)移动时每次只会改变至多两个叶子的\(dp\)值,因此使用动态\(dp\)实现即可,复杂度\(O(n\log^2n)\),可以获得\(100\)分。
在具体实现中,由于深度奇偶性不同导致转移不同,故可以令\(f_i'=[\mbox{i点深度为奇数}]f_i+[\mbox{i点深度为偶数}](1-f_i)\),这样转移就可以统一为\(f_u'=\prod(1-f_v')\)。
此外在动态\(dp\)的过程中可能会出现乘\(0\)后除\(0\)的问题,需要开一个\(pair\)记录\(dp\)值非零部分的乘积以及乘\(0\)的个数,从而实现信息可减。
code
Day2T1 开关
先求出\(n\)次操作后使开关状态合法的方案数,其对应的指数型生成函数为(记\(P=\sum_{i=1}^np_i\))\[F(x)=\prod_{i=1}^n\frac{e^{\frac{p_ix}{P}}+(-1)^{s_i}e^{-\frac{p_ix}{P}}}{2}\]
然而这个方案数包含了一些多次达到合法状态的方案,需要将其排除。考虑\(n\)次操作后回到原状态的方案数对应的指数型生成函数:
\[G(x)=\prod_{i=1}^n\frac{e^{\frac{p_ix}{P}}+e^{-\frac{p_ix}{P}}}{2}\]
在具体实现中,只需要记录\(F(x)=\sum_{i=-P}^Pa_ie^{\frac{ix}{P}}\)中的\(a_i\)系数即可,\(G(x)\)同理。这一部分暴力实现的话复杂度为\(O(nP)\)。
再记\(H(x)\)为答案的生成函数,令\(F(x),G(x),H(x)\)对应的普通生成函数分别为\(f(x),g(x),h(x)\),可知\(g(x)h(x)=f(x)\)。
(原本这里误写成了\(G(x)H(x)=F(x)\),实际上由于答案是操作序列的一段前缀,因此\(g\)与\(h\)的关系应当为直接拼接而非组合相乘,对应的也应为普通生成函数的乘法。感谢@leoiter指正。)
关于指数型生成函数与普通生成函数的转化:当\(F(x)=\sum_{i=-P}^Pa_ie^{\frac{ix}{P}}\)时,\(f(x)=\sum_{i=-P}^P\frac{a_i}{1-\frac{ix}{P}}\)。
此时要求的答案为\(h'(1)\),使用公式\((\frac{f(x)}{g(x)})'=\frac{f'(x)g(x)-f(x)g'(x)}{g^2(x)}\)计算答案。但是\(x=1\)代入\(f(x)\)与\(g(x)\)后函数不收敛。考虑将\(f(x)\)与\(g(x)\)同乘上\(\prod_i(1-\frac{ix}{P})\)结果不变,此时\(f(x)=\sum_ia_i\prod_{j\neq i}(1-\frac{jx}{P})\),可以计算出\(f(1)=a_P\prod_{i\neq P}(1-\frac{i}{P})\),\(f'(1)=-(\prod_{i\neq P}(1-\frac{i}{P}))(\sum_{i\neq P}\frac{a_i}{1-\frac{i}{P}}+a_P\sum_{i\neq P}\frac{\frac{i}{P}}{1-\frac{i}{P}})\)。
(以上默认\(i,j\in[-P,P]\cap\mathbb{Z}\))
推导过程中可能需要用到的东西:\((\prod_i(1+a_ix))'=\sum_ia_i\prod_{j\neq i}(1+a_jx)\)。
令\(g(x)\)的对应系数为\(b_i\),不难发现实际上\(a_P=b_P=\frac{1}{2^n}\),因而可以简化一些运算,最终的答案为\(2^n\sum_{i\neq P}\frac{b_i-a_i}{1-\frac{i}{P}}\)。
code
Day2T2 语言
对每个点求所有覆盖该点的链的链并大小,加起来除以\(2\)就是答案。
树上差分,即对于链\((x,y)\)在\(x\)和\(y\)处加入这两个点,在\(fa_{lca(x,y)}\)处删去(注意判出现次数)。线段树合并即可,复杂度\(O(n\log n)\)。
code
Day2T3 浙江省选
显然每个人就是一条直线。对所有人求个半平面交(简易版,因为斜率均为正),然后那些在半平面边界上(包括一个整点)的人可以拿第一名。
接着考虑剩下的人。如果剩下的某个人想要拿第二名,那么他至少要在剩下的人中拿第一。对剩下的所有人做半平面交,得到的就是所有第二名的候选人,接着拿所有第一名在这个半平面上二分求出他会让哪段\(x\)坐标范围的名次\(+1\),即做一次区间覆盖。当半平面边界上的某人只被不超过\(1\)个人覆盖时,他就可以拿到第二名。
第三名至第\(m\)名依此类推,只需要做\(m\)次半平面交+二分即可,复杂度\(O(mn\log n)\)。
实现上有些小细节,具体可以参照代码。code
HNOI
link
十二省联考
Day1T1 异或粽子
把所有右端点丢到堆里,每次取出最大的即可,需要实现可持久化\(Trie\)树上求异或第\(k\)大。复杂度\(O(n\log a_i+k\log n+k\log a_i)\)。
code
Day1T2 字符串问题
\(A_x\)向所有它支配的\(B_y\)连边,而\(B_i\)向所有以它为前缀的\(A_j\)连边。上述方式建图后,最终答案记为图中以\(A\)串长度为权值的最长路。
直接暴力建边的边数是\(O(n^2)\)级别的,显然难以承受。考虑优化这个建边过程。
建\(SAM\)后从上往下连边就行啦,注意同一个节点内的所有串要按照长度排序(长度相同时\(B\)串要排在\(A\)串的前面)后串成一条链。这样建图的总点数不超过\(2n_a+n_b+SAM\)节点数。
此外:
数据千万条,清空第一条。
多测不清空,爆零两行泪。
code
Day1T3 骗分过样例
我一定是闲得发慌才去写这种题的\(Q\omega Q\)
前\(5\)个点是输入\(x\)求\(19^x\%p\),\(x\)的范围比较大(超过long long
的值域范围)所以直接读入字符串后十进制快速幂就行了。\(4,5\)两个点需要自己猜模数。
\(6,7\)两个点是爆int
的错误示例。并不能快速幂,不过通过各种途径可以发现循环节不长,所以直接把循环节打出来就好了。
\(8,9,10\)是区间求质数。直接大力\(\mbox{Miller_Rabin}\)即可。
\(11,12,13\)是区间求\(\mu\)。可以先分解三次根号\((10^6)\)范围内的质因子,然后最多最会剩下\(2\)个质因子,先判断是否相等(完全平方数),再\(\mbox{Miller_Rabin}\)判断其是否是质数即可。这部分跑得比较慢,因此面向数据卡了波常,代码中所有难以理解的部分均为卡常的迹象。
\(14,15,16\)区间求原根。设\(p-1\)有\(k\)种不同质因子,那么存在一种\(O(nk\log p)\)的判断方法,同时也存在一种\(O(pk)\)的方法。两者结合就行了。
code
Day2T1 皮配
在没有任何城市限制与偏好限制的情况下,对一个人数为\(s\)的学校定义其二元生成函数\(1+x^s+y^s+x^sy^s\)。将所有学校的生成函数\(\prod\)起来,由于总人数已知,所以\(C_0,C_1,D_0,D_1\)等价于对\(x\)与\(y\)的指数做了一定的范围限制(在某个\([l,r]\)之间)。
对于一座没有任何偏好的城市,设其学校人数集合为\(S\),则其生成函数为\((1+y^{sum(S)})\prod_{s\in S}(1+x^s)=\prod_{s\in S}(1+x^s)+y^{sum(S)}\prod_{s\in S}(1+x^s)\)。若存在一些学校存在偏好,则该学校对应在\(1\)或\(y^{sum(S)}\)中的\(1\)或\(x^s\)项要被删去,而这并不会影响到其余没有偏好的学校(因为对于其余的学校你仍可以提一个\((1+x^s)\)项出去),而所有无关的项中\(x\)和\(y\)相对独立,所以可以先分别\(O(nm)\)地计算没有偏好的学校及城市的生成函数,再\(O(km^2)\)地暴力\(dp\)存在偏好的学校的生成函数。由于限制了单所学校的人数上限,所以实际上复杂度只有\(O(k^2ms_i)\)。
code
Day2T2 春节十二响
根节点显然自成一组,所以只需要考虑合并根的若干子树。显然最优策略会是:两棵子树内最大值分在一组,次大值分在一组......可以通过数学归纳证明一定不存在更优操作。
由于需要支持动态插入(根节点),因此考虑使用堆来维护子树内的决策。使用长链剖分,每次计算时先\(O(1)\)继承长儿子,再暴力地合并其余儿子,复杂度可以做到\(O(n\log n)\)。
使用priority_queue::swap
可以做到\(O(1)\)交换两个堆。
(其实std::swap
复杂度也是\(O(1)\)的,感谢@EndSaH指正。)
code
Day2T3 希望
枚举一个点,求所有救援队都覆盖其的方案数,但这样显然算重了,因此需要容斥。考虑一种方案下能被每个救援队都覆盖的点一定是一个连通块,其点数\(-\)边数\(=1\),因此我们只需要对每个点求答案,再对每条边求答案就行了。具体的,设\(f_{i,j}\)表示\(i\)点子树中距离\(i\)不超过\(j\)的连通块个数,\(g_{i,j}\)表示\(i\)点子树外距离\(i\)不超过\(j\)的连通块个数,转移如下:
\[f_{i,j}=\prod_{v \in son(i)}(f_{v,j-1}+1)\]
\[g_{i,j}=g_{fa_i,j-1}\prod_{v\in son(fa_i)}(f_{v,j-2}+1)+1\]
这样的时空复杂度均为\(O(nL)\)。code
考虑优化。
首先\(f\)的转移可以长链剖分。在长剖的过程中,每当暴力合并一个轻儿子后,都需要将长链的一段后缀乘上一个定值,可以转为前缀乘上其逆元,这样暴力扫前缀复杂度才是对的。由于后缀乘上的值可能是\(0\)不存在逆元,因而需要额外开两个变量记录一段后缀的值变成了多少。
\(g\)的转移需要分轻重儿子分别考虑。首先可以发现的是,若\(i\)点距离子树内最深点长度为\(d\),则\(g_i\)中只有状态\(g_{i,L-d...L}\)是有用的,也就是说\(g_i\)需要保存的长度也只有\(i\)点子树内最深深度那么长。对于所有轻儿子,只需要记录前后缀的信息即可,具体来说可以对\(f\)实现可回退化,求\(g\)的时候倒着访问所有儿子,这样每次对\(f\)的操作回滚即可得到前缀信息,同时边做边维护后缀信息即可。重儿子直接暴力扫一遍最终维护出的后缀信息即可,复杂度为最长轻儿子长度。
由于涉及到求逆元复杂度仍然是\(O(n\log mod)\),不过可以发现每次需要求逆的东西都是某个\(f_{i,L}\),而这个东西可以预处理\(dp\)一遍直接求出,因而可以做到离线\(O(n)\)求\(n\)个数的逆元。
讲道理这道题难点不在算法而是在实现吧,相信大家应该都知道怎么做,至于怎么写出来那就得各凭本事了呢。
code
GX/GZOI
Day1T1 与或和
拆位考虑,假设所有数字都是\(0/1\)。一个子矩阵与为\(1\)当且仅当它全都是\(1\),或为\(1\)当且仅当存在至少一个\(1\),反过来就是没有\(1\)。因此求全\(1\)全\(0\)子矩形个数就好了,复杂度\(O(n^2\log a_i)\)。
code
Day1T2 宝牌一大堆
(出这种题有意思吗)
反正大力\(dp\)就好了吧,相信大家对于麻将形式的\(dp\)已经很熟悉了。
题中给出的\(15\)至\(18\)张牌的和牌方案,其实等价于是用一个杠子代替了一个面子,因而可以统一为一种\(dp\),即\(f_{i,j,k,x,y}\)表示考虑了前\(i\)种牌,有\(j\)个\(i-1\)开头的顺子,\(k\)个\(i\)开头的顺子,已经出现了\(x\)个面子/杠子和\(y\)个对子情况下的最大分数,其中\(j,k\le2,x\le4,y\le1\)。此外就只剩下七对子和国士无双两个简单\(dp\)了。
code
Day1T3 特技飞行
显然强行二合一。第一问是给出平面上的若干点和\(k\)个关键点,每个关键点有个覆盖范围\(r\),可以覆盖与其曼哈顿距离不超过\(r\)的所有点,求有多少个点会被至少一个关键点覆盖。显然曼哈顿转切比雪夫(就是坐标轴旋转\(45^\circ\))后覆盖范围就是个矩形,因此排序+扫描线可以做到\(\log n\)。
第二问是求最多可以做多少次擦肩而过,因为显然如果每次都做对向交换的话是一定合法的。这其实等价于是问最少做多少次对向交换。考虑全部做擦肩而过后在终点处得到的相对顺序排列\(p\),每次的对向交换在最终的排列\(p\)上的作用体现即为交换了某两个元素的位置。因为我们只需要用最小的交换次数将\(p\)还原成元排列即可。
code
Day2T1 逼死强迫症
设\(f_{i,0/1/2}\),然后矩阵转移即可。
code
Day2T2 旅行者
对每个点求出到达这个点最近的关键点\(f_i\)以及从这个点出发能到达的最近关键点\(g_i\),然后枚举一条边\(u\to v\),若\(f_u\neq g_v\)则可以用这条边更新答案。
code
Day2T3 旧词
权值差分后主席树维护链并即可。当然也可以离线线段树做到空间线性。
code
BJOI
Day1T1 奥术神杖
权值转对数后相当于求权值的平均值,因此使用分数规划。对所有串建立\(AC\)自动机后\(dp\),复杂度\(O(ns\alpha\log\mbox{eps}^{-1})\),其中\(\alpha\)为字符集大小,\(\mbox{eps}\)为设定的精度范围。
能过就行了。
code
Day1T2 勘破神机
第一个数列显然就是\(f_1=1,f_2=2\)的斐波那契数列。第二个数列只有偶数项非零,单独拿出来后有\(g_1=3,g_2=11,g_n=4g_{n-1}-g_{n-2}(n>2)\),可以打表找规律或强行\(BM\)或oeis大法好。
显然两者均为线性常系数齐次递推式,可以根据其特征根解得其通项式。一般的,设其特征根为\(x_1,x_2(x_1\neq x_2)\),则通项式为\(f_n=c_1x_1^n+c_2x_2^n\)。特殊的,题中所给出的两个数列的特征根以及对应系数分别为:
\[\begin{cases}x_1=\frac{1+\sqrt 5}{2}\\x_2=\frac{1-\sqrt5}{2}\\c_1=\frac{5+\sqrt 5}{10}\\c_2=\frac{5-\sqrt5}{10}\end{cases}\]
以及
\[\begin{cases}x_1=2+\sqrt3\\x_2=2-\sqrt3\\c_1=\frac{3+\sqrt3}{6}\\c_2=\frac{3-\sqrt3}{6}\end{cases}\]
接下来的推导均采用一般形式。
\(\binom nk\)可以被认为是一个关于\(n\)的\(k\)次多项式,即\(\binom nk=\frac{1}{k!}\prod_{i=0}^{k-1}(n-i)\)。
题目要求的是\(\sum_{i=1}^n\binom{f_i}{k}\),可以转化为求\(\sum_{i=1}^nf_i^{1...k}\),因而只考虑怎么求\(\sum_{i=1}^nf_i^k\)。
\[\sum_{i=1}^nf_i^k=\sum_{i=1}^n(c_1x_1^i+c_2x_2^i)^k\\=\sum_{i=1}^n\sum_{j=0}^k\binom kj(c_1x_1^i)^j(c_2x_2^i)^{k-j}\\=\sum_{i=1}^n\sum_{j=0}^k\binom kjc_1^jc_2^{k-j}(x_1^jx_2^{k-j})^i\\=\sum_{j=0}^k\binom kjc_1^jc_2^{k-j}\sum_{i=1}^n(x_1^jx_2^{k-j})^i\]
后面是个等比数列求和,特判下\(q=1\)的情况就好了。
总复杂度\(O(Tk^2\log n)\)。比较难受的一点是\(998244353\)下不存在\(3\)和\(5\)的二次剩余,因而需要扩域,即使用一个\(pair(a,b)\)来表示\(a+b\sqrt 3\),其中\(a,b\in\mathbb{R}\)。
code
Day2T1 排兵布阵
很显然是个背包,每次只枚举有用的转移点,暴力转移即可。
code
Day2T2 光线
对于两面镜子\((a_1,b_1)\)与\((a_2,b_2)\),考虑将其合为一面镜子\((\frac{a_1a_2}{1-b_1b_2},b_1+\frac{a_1^2b_2}{1-b_1b_2})\)。
上面的式子其实很好推导,只需要枚举光在两镜之间反射了多少次,即可得到一个等比数列求和的形式,化简后即可得到上式。
把所有镜子自下而上合并即可。
code
Day2T3 删数
对于\(i\in[1,n]\),若数列中含有\(cnt_i\)个\(i\),则进行对区间\([i-cnt_i+1,i]\)的区间覆盖。最终的答案就是未被覆盖部分的长度。
然后就只需要考虑如何维护这个东西了。区间覆盖可以认为是区间\(+1\),计算答案时只需要数区间内最小值的个数即可(最小值不会小于\(0\))。由于存在值域平移的操作,因此在线段树中只维护真实值范围在\([1,n]\)的区间覆盖就行了。复杂度\(O(n+m\log n)\)
code
SNOI
Day1T1 字符串
\(n=10^6\)时倍增求后缀数组大约要\(0.6\sec\)。(虽然也能过就是了)
其实需要用到的只有相邻两个后缀的\(lcp\),直接\(O(n)\)从后往前预处理即可。
接着来就是一个std::stable_sort
的事情了。
code
Day1T2 数论
\(x\to (x+P)\%Q\)会形成\(\gcd(P,Q)\)个长度为\(\frac{Q}{\gcd(P,Q)}\)的环。
枚举\(x\%P\)的值(即枚举\(a_i\)),问题变成求有多少\(0\le x\le \lfloor\frac{T-1-a_i}{P}\rfloor\)满足\((Px+a_i)\%Q\in\{b_i\}\)。其实就是求从某个点出发走若干步(\(\lfloor\frac{T-1-a_i}{P}\rfloor\)步)能到达的所有点的点权和。随便讨论一下即可。复杂度\(O(P+Q)\)。
code
Day1T3 通信
费用流暴力建图点数\(O(n)\)边数\(O(n^2)\)。
随便分治一下可以将点数和边数都变成\(O(n\log n)\)级别。然后...就能跑了?
code
Day2T1 纸牌
恭喜SN喜题第三道麻将题!不知道下一道将花落谁家呢?
直接\(9\times9\)大力矩乘即可,复杂度\(O(9^3X\log n)\),当然其实也可以做到\(O(9^2X\log n)\)。
code
JSOI
T1 精准预测
以下用\((t,x)\)表示\(t\)时刻\(x\)这个人活着的状态,\((t,\overline{x})\)表示\(t\)时刻\(x\)这个人死亡的状态。
很显然的\(\text{2-sat}\)建图。对于第一种限制关系,连边\((t,x)\to(t+1,\overline{y}),(t+1,y)\to(t,\overline{x})\)。对于第二种限制关系,连边\((t,x)\to(t,\overline{y}),(t,y)\to(t,\overline{x})\)。此外还需要连边\((t,\overline{x})\to(t+1,\overline{x}),(t+1,x)\to(t,x)\)。
如此建图后每个\(i\)的答案即为从\((T+1,i)\)出发不能到达的\((T+1,\overline{j})\)的\(j\)的数量\((j\neq i)\)。当然还需要满足\(i,j\)两者有可能活下来,即\((T+1,i)\)无法到达\((T+1,\overline{i})\),\((T+1,j)\)无法到达\((T+1,\overline{j})\)。
暴力建图的点数为\(2n(T+1)\)。首先可以发现建出来的图是一张\(\text{DAG}\),同时只有\(m\)条限制中被用到的点是有用的,其余很多点均只有一条连向上一时刻或者是下一时刻的出边,可以减小图的规模至\(2m+2n\)。当然这并不是最优的,反正能过就行了。
问题转化为求\(\text{DAG}\)上每个点出发能到达哪些关键点。这个问题目前只还能做到\(\text{bitset}\)复杂度,因此总时间复杂度\(O(\frac{nm}{\omega})\),看上去能过。
空间开不下?分多次做不就好了吗。
code
T2 神经网络
姑且算是个二合一。
第一问是对每棵树求出将这棵树划分成\(1...n\)条链的方案数。注意在这里链是有方向的,因此每选取一条长度大于\(1\)的链方案数就要乘\(2\)。这个可以用\(O(n^2)\)的树\(dp\)解决。
第二问是求将所有树划分的若干条链摆成一个环,要求相邻不能同色(来自同一棵树)的方案数。一个显然的想法是容斥掉相邻不同色,即强制若干对相邻同色,容斥系数显然应为\(\pm1\)。
先假设摆成的不是环而是链,即不考虑首尾不同色也不考虑循环同构。考虑用指数型生成函数分配序列上的位置。对于一棵\(n\)个节点的树,设将其划分成\(i\)条链的方案数是\(f_i\),那么其对应的指数型生成函数应为:
\[\sum_{i=1}^nf_ii!\sum_{j=1}^i(-1)^{i-j}\binom{i-1}{i-j}\frac{x^j}{j!}\]
然后考虑怎么拓展到环上。我们钦定一种颜色(一棵树)作为环的开头(即作为第一个元素),如果这种颜色被分了\(i\)段,那么这种方案在最终的答案里就会被算\(i\)次。因此我们将这种颜色的指数型生成函数设为:
\[\sum_{i=1}^nf_i(i-1)!\sum_{j=1}^i(-1)^{i-j}\binom{i-1}{i-j}\frac{x^{j-1}}{(j-1)!}\]
然而这样没有考虑首尾不同色。不过我们只需要减去强制首尾同色的方案就好了:
\[\sum_{i=2}^nf_i(i-1)!\sum_{j=2}^i(-1)^{i-j}\binom{i-1}{i-j}\frac{x^{j-2}}{(j-2)!}\]
上下两个函数做差后得到的就是这种被钦定的颜色对应的指数型生成函数。
把所有函数(暴力地)卷起来即可得到答案。
code
T3 节日庆典
一个位置作为最小循环表示的起始位置的一个必要条件为以其为起始位置的后缀是一个最小后缀。如果做过这个题的话应该知道一个字符串的最小后缀只有至多\(\log n\)个,所以暴力维护出这个备选集合再比较就行了。
简单证一下这个性质:考虑相邻的两个最小后缀\(i,j\),若\(|j|<|i|<2|j|\),则说明\(i=AAB,j=AB\),其中\(A,B\)均为字符串,且\(B\)是\(A\)的一个严格前缀。此时考虑\(i=AAB,j=AB,k=B\),可以发现无论如何最小后缀都会在\(i\)和\(k\)之间产生,\(j\)不可能成为最小后缀,由此说明相邻两个最小后缀之间一定至少相差\(1\)倍,因此数量不超过\(\log n\)。
然而\(n\)的规模大得有些超越想象,传统后缀数据结构可能难以胜任。可以考虑退而求其次,在\(O(n)\)的时间复杂度内求出原串的所有后缀与原串的\(lcp\)长度,即使用所谓的\(\text{Z-algorithm}\)。由于备选集合内的后缀一定存在前缀关系(较短串一定是较长串的前缀),因此比较时需要用到的也就只有每个后缀与原串的\(lcp\)了。
code
TJOI
Day1T1 甲苯先生的字符串
矩乘即可。
code
Day1T2 甲苯先生的滚榜
动态开点线段树+树状数组维护即可。
code
Day1T3 唱、跳、rap 和篮球
由于非法串不可能相交,所以可以直接枚举非法串至少出现多少次,剩下位置随便填,容斥即可得到答案。设出现非法串出现至少\(i\)次的方案数是\(dp_i\),则答案为\(\sum_{i=0}^{min\{n/4,a,b,c,d\}}(-1)^i\binom{n-3i}{i}dp_i\)。
考虑求\(dp_i\)。方案数显然就是四个指数型生成函数卷起来,即\(dp_i=[\frac{x^{n-4i}}{(n-4i)!}](\sum_{i=0}^{a-i}\frac{x^i}{i!})(\sum_{i=0}^{b-i}\frac{x^i}{i!})(\sum_{i=0}^{c-i}\frac{x^i}{i!})(\sum_{i=0}^{d-i}\frac{x^i}{i!})\)。暴力计算复杂度\(O(n^3)\),可以考虑维护前两个函数的乘积与后两个函数的乘积,每次\(i\)改变时只需要\(O(n)\)即可修改两个多项式,求多项式的某一项系数也可以直接\(O(n)\),总复杂度\(O(n^2)\)。
code
Day2T1 大中锋的游乐场
设状态\((u,x\in[-k,k])\),最短路即可。
code
Day2T2 甲苯先生和大中锋的字符串
建\(\text{SAM}\)即可。
code
Day2T3 甲苯先生的线段树
先求出路径上所有点编号和\(n\)。设路径深度最小的点为\(x\)。
以\(x\)为中点,枚举左右两侧链的长度\(L,R\)(\(L,R\)可能为\(0\))。显然在确定了\(n\)和\(L,R\)后,\(x\)也唯一确定了,因为在\(L,R\)已知的前提下,\(x\)的不同取值对应的\(n\)的可行范围是无交的。由于\(x\)是确定的,所以我们可以把问题规约到\(x=1\)的情况上来。
对于\(x=1\),我们只需要安排一下左右两棵子树长成什么样即可。首先\(n\)的取值下界是\(2^{L+1}+3\times 2^R-4\),之后每当在深度为\(d\)处选择了右子树进入,就会给\(n\)值加上\(\sum_{i=0}^d2^i=2^{d+1}-1\)的贡献。这个问题等价于我们要安排两个长度分别为\(L-1\)和\(R-1\)的\(01\)串,其第\(i\)位(\(0\)下标)的位值为\(2^{i+1}-1\),使得这两个字符串的总权值加上\(n\)的取值下界后恰等于\(n\),求安排两个\(01\)串的方案数。这个问题直接数位\(dp\)即可(或者像我一样懒直接写记搜)。
对于\(x\neq 1\),此时\(n\)的取值下界是\((2^{L+1}+2^{R+1}-3)x+2^R-1\),令\(k=(2^{L+1}+2^{R+1}-3),b=2^R-1\),此时\(x\)的取值一定为\(\lfloor\frac{n-b}{k}\rfloor\),于是便可以规约为\(n'=(n-b)\%k,x=1\)的问题。
总复杂度大概是\(O(\log^4n)\)至\(O(\log^5n)\)。
code
SDOI
Day1T1 快速查询
维护全局标记\((a,b)\)表示维护的数\(x\)的实际值为\(ax+b\),这里需要始终保证\(a\neq 0\),初始时\(a=1,b=0\)。
单点修改成\(val\)就把维护的值改成\(\frac{val-b}{a}\)。注意需要逆元需要实时维护。
加法直接加。
乘法若\(val\neq 0\)就直接乘,注意加法标记也要乘。否则操作就是全部赋值为\(0\)。
赋值为\(val\)就把维护的数组全部清零,然后令\(a=1,b=val\)。显然清零的复杂度不会超过单点修改的复杂度。
查询直接查。
总时间复杂度\(O(q\log p+tq)\)。
code
Day1T2 染色
首先有个很显然的没分裸暴力,记\(f_{i,j,k}\)表示\(dp\)到第\(i\)列,这一列的两个格子的颜色分别是\(j,k\)的方案数,转移显然。
考虑子任务\(1,2\)。称包含已染色格子的列为关键列,我们只需要考虑关键列之间的转移即可。由于关键列有一种颜色已经确定,所以\(dp\)状态中就只需要记另外一个格子的颜色即可,这样的状态数就只有\(O(nc)\)了。转移时枚举当前格子的颜色,可以做到\(O(1)\)转移。
在这里需要求出这些东西的方案数(假设中间\(0\)的列数为\(z\)):
\(\begin{pmatrix}x&0&\cdots&0&x\\y&0&\cdots&0&y\end{pmatrix}\)
\(\begin{pmatrix}x&0&\cdots&0&y\\y&0&\cdots&0&x\end{pmatrix}\)
\(\begin{pmatrix}x&0&\cdots&0&x\\y&0&\cdots&0&w\end{pmatrix}\),它等价于\(\begin{pmatrix}x&0&\cdots&0&w\\y&0&\cdots&0&y\end{pmatrix}\)
\(\begin{pmatrix}x&0&\cdots&0&y\\y&0&\cdots&0&w\end{pmatrix}\),它等价于\(\begin{pmatrix}x&0&\cdots&0&w\\y&0&\cdots&0&x\end{pmatrix}\)
\(\begin{pmatrix}x&0&\cdots&0&w_1\\y&0&\cdots&0&w_2\end{pmatrix}\)
记\(g_{z,0/1/2/3/4}\)分别表示上述五种情况下给中间的\(0\)染色的合法方案数。(代码中\(g_z\)记的是\(z-1\)个\(0\)的方案数)
转移有点小复杂可以参考代码。
求出\(g_z\)之后就可以愉快地\(dp\)了。每遇到一个关键列就大力讨论转移,复杂度\(O(nc)\)。
对于子任务\(3,4\)中存在的两个格子均已染色的列,称其为分割列,可以发现分割列两侧的方案数独立,因此需要实现分割列到关键列、关键列到分割列的转移,分割列到分割列之间直接讨论一下颜色是否相同乘上方案数就行了。
\(O(nc)\)地实现了上述内容即可获得\(96\)分的好成绩。发现我们对与维护的\(dp\)数组做的所有操作均为前一道题中的操作,因此Ctrl-C
Ctrl-V
再随便改改即可通过此题。
96分code
100分code
Day1T3 世界地图
对每个前缀\(i\)维护出前\(i\)列的\(\text{MST}\)将第一列和第\(i\)列的点设为关键点的虚树,虚树边权为原树的路径最大值。合并的时候只需要对这个\(O(n)\)级别的虚树做一次最小生成树就行了。复杂度\(O(n(m+q)\log n)\)。
code
Day2T1 热闹的聚会与尴尬的聚会
考虑如下构造方法:每次从图中选取一个度数最小的点,将其以及与其相邻的点删去。设该操作一共进行了\(q\)次,第\(i\)次选取了点\(a_i\),删除了包含点\(a_i\)在内的共\(b_i\)个点,假设\(b_t\)为\(\{b_i\}\)的最大值,那么可以选取在第\(t\)次及以后删除的点作为\(P\)集合(即热闹的舞会),选取\(\{a_i\}\)作为\(Q\)集合(即尴尬的舞会)。
不难发现\(Q\)一定是一个独立集,且\(|Q|=q\)。\(\sum_{i=1}^qb_i=n\),\(P\)集合此时的\(p\)值恰好为\(b_t-1\)。显然\((p+1)b_t\ge n+1\),因此这种构造方法是可行的。
用智障的方法维护度数最小的点,复杂度\(O(Tm\log n)\)。
code
Day2T2 移动金币
阶梯博弈。只有奇数层的石子有用,因此只需要考虑奇数层,偶数层用组合数分配即可。
后手必胜当且仅当奇数层石子数异或和为\(0\),也就是说每个二进制位的\(1\)的个数都是偶数。搞\(\log n\)个只有\(\frac{\frac{m+1}{2}}{2}+1\)项有值的多项式(暴力地)乘起来就好了,复杂度\(O(nm\log n)\)。
code
Day2T3连续子序列
\(\text{Thue-Morse}\)序列有许多许多优美的性质(所以这题感到无从下手?)可以参考A010060。
这里我们用到其中一条有趣的性质:\(\text{Thue-Morse}\)序列的另一种生成方式。
考虑先令\(T.M.=\{0\}\),随后每次用\(01\)替换原序列中的\(0\),用\(10\)替换原序列中的\(1\),每次替换后序列长度翻倍,由此反复操作即可得到\(\text{Thue-Morse}\)序列,且每次操作后均可以得到一个其长度为\(2^k\)的前缀。
这种构造方法基于\(0\to01,1\to10\),可以将这个过程反过来,即\(1\gets 01,0\gets 10\),可以发现这个操作就是把字符两两划分成组后映射为\(0/1\)。注意对于任意一个给定的长度大于\(2\)的串\(s\),其均有两种划分方案,当然如果某种划分方案中存在一组两个字符相同,那么这种划分就是不合法的。
因此我们只需要考虑对串\(s+k\)(表示在串\(s\)后面加上\(k\)个字符)进行上述的操作即可。由于每次\(|s|\)和\(k\)都会减小一半,因而使用记忆化搜索的总状态数为对数级。注意要对一些递归边界进行特判。
code