训练记录PART3 2018.3.14~4.25
友情提醒:大部分题选自opentrains,以后有训练需要的同学慎重查看。
3.14 2016 Petrozavodsk Winter- JAG Contest
D
题意:有\(N(\leq 1000)\)个柱子,每一个高度是\(h_i\),每一根被标记为要删除1/不能删除0。每次可以选择连续的一段并选定一个\(H\),把其中\(h_i \geq H\)的柱子全删掉(注意,0柱子一定不能符合这个要求),然后剩下的柱子继续合并。重复操作使得最后只剩下0柱子。求最小操作步数。
题解:不妨每次考虑高度最矮的柱子(一样的话,优先1柱子)。如果它是0柱子,那么我们可以直接无视它,删除它继续递归求解(因为我只要保证每次H比它的h大一些即可)。如果它是1柱子,注意到截止最后时,它必然被删过了;考虑删它的那一次操作,我们显然要尽可能的让这一步操作获得更大的收益——所以我们找到它左右的第一次出现的柱子,然后同时删除这一段中间的所有柱子。
G
题意:三维空间里有一个\(A*B*C(\leq 10^6)\)的长方体,由111的小方块构成。给出\(N(\leq 20000)\)个障碍点,求它将长方体划成了几个不连通的区域。
题解:先考虑二维时的情况。对于每一个障碍点,我们把它八连通的点都抠出来,称为“关键点”;当然这些点还不够,我们再将每个这样的点映射到四个边界上,把那些点也加入“关键点”集合。最后对于所有关键点,每次找一个点周围的四个点,暴力并查集并一下,得到的连通块个数就是答案。
三维可能难想一点。注意到,棱长最多有\(10^6\),所以必须优化关键点的个数。后来结论是:先扣出来每一个障碍的“26连通”点,再分别将它们投影到6个平面上得到新关键点;再把这些点投影到棱上,再加一波关键点。然后类似二维,6个方向上找一找,暴力并查集一下。要常数优化才能通过本题。
K
题意:\(N(\leq 1000)\)个人打淘汰制比赛,每一个人有一个绝对实力值\(A_i\)。。每次两个人比赛时,产生\(|A_i-A_j|\)的无聊值,然后\(A\)大的获胜。构造一棵深度不超过\(D(\leq 50)\)的二叉树(安排\(N-1\)场比赛),使得总无聊值最小。
题解:猜测最优解里,每次连续一段的人放在同一棵子树里。然后就能写出一个\(N^3*K\)的DP了。然后这是满足四边形不等式的(坑坑坑),所以复杂度就少了个N。
3.16 2016 Petrozavodsk Winter - Nizhny Novgorod SU Contest
A
题意:给出长度为\(N\)的数组\(y\)和\(N^2\)数组\(C\),且\(x_i=y_i+\sum \limits_j C_{i,j}\)。再给出数组y',现在要构造C'和x',使得它们依然满足原来的式子,而且\(\forall j \frac{\sum C_{i,j}}{x_j}=\frac{\sum C'_{i,j}}{x'_j}\)。\(N \leq 3000 , 1 \leq C_{i,j} \leq 1000 , 10^7 \leq y',y'_i \leq 10^9\)
题解:y和C的大小就很可疑。传统做法不能快速地求出C。那么我们可以考虑迭代,初始时设C'=C,然后每次调整一下。
D
题意:\(N(\leq 100)\)维空间里有\(N\)个线性无关的向量\(A_i\)。对于每一个向量\(i\),只给出一个长度为\(M(\leq 100)\)的严格单调的数组\(C_{i,j}\)(保证 \(\forall i \exists j C_{i,j}=0\))。交互题,每次对于向量i指定一个\(p_i(1 \leq p_i \leq M)\),返回向量 \(q=\sum C_{i,p_i}*A_i\)。在120次询问之内算出向量p,使得返回的是零向量。
题解:先询问\(N+1\)次,我们可以得到\(A_i\)的单位向量。然后,每次如果给出一个向量\(p\),我们可以通过高斯消元,计算出\(C_{i,p_i}\),而且向量之间是独立的。所以每次把所有向量一起二分即可。可以先算出A的逆矩阵,加速求解。
3.18 2016 Petrozavodsk Winter - Saratov SU Contest
B
题意:给定一张二分图。甲乙分别在图的左侧和右侧。开始一个球在左侧固定的一个点。每次甲可以沿着一条边推到右边,乙再沿一条边推过来。走过一条边后,它就会被删除;最后谁不能动谁就输。求甲必胜条件。
题解:我们不妨设甲赢了。观左边经过的所有点,除了起点经过了奇数次,别的肯定都经过了偶数次。我们设右侧经过的点集为S。所以,如果右侧不存在一个点集S,使得与其相关的左端点包含了起点且满足度数要求,甲必输;存在的话,甲可以无视除S外的所有点(即每次强制去S),最后必胜。
3.21 2015 MIPT Workshop Open - AMPPZ-2015
G
题意:平面上有\(N(\leq 250000)\)个点,每一个点有一种颜色。求最远的颜色不同的点对。
题解:好像类似的题七月集训里做过蛤。
先考虑只有两种颜色。分别对其做一个凸包,转化为两个凸包上的最远点对,即求最大的\(|\vec{b_j}-\vec{a_i}|\)。将凸包\(a\)关于原点对称,可以把-变成+。注意到这就是闵可夫斯基和,\(\vec{b_j}+\vec{a_i}\)会正好构成一个点数为\(n+m\)的新凸包。只需找到必定在新凸包里的一个点,然后把两个凸包的边按极角序顺次拼起来即可。
多种颜色的话,每次启发式地合并最小的两个,效率就是\(O(N log^2 N)\)。如果顺便维护每一个凸包按x轴排序的点集,每次求凸包时就可以归并;构闵可夫斯基和时也可以把两个凸包的线段归并合并——所以理论可以做到\(O(N log N)\)。
K
题意:对于一个1~N(\(\leq 50000\))的排列,把它们顺次排列,数字是它们的高度。问存在多少个这样的排列,使得从左侧望过去能看到\(A\)个,从右侧望过去能看到\(B\)个(\(A,B \leq 100\))。有\(10^5\)组数据。
题解:如果对于每次询问,枚举最高的那个在哪,那么可以得到一个计算答案的卷积式:\(Ans=f_{i-1,A-1}*f_{n-1-i,B-1}*C_{n-1}^{i-1}\)。其中\(f_{i,j}\)表示1~i的排列里从一侧能看到j个的方案数。
按这种方式想就走入死胡同了……考虑直接统计答案。对于一个排列,我们先随意放一个n,然后再从n-1往1填。我们会发现,每次填时,可以填在最左边(A+1),最右边(B+1),否则中间(无贡献);而且填在中间的方案数是n-i-1。对于一种填数的方案,把中间的方案数乘起来,就是它对应的排列数。
所以我们可以设\(f_{i,j}\)表示填i-1个数,填在最左/右边的有j个时的总方案数。对于一组询问,答案就是\(f_{n,A+B-2}*C_{A+B-2}^{A-1}\)。
3.25 Pony.AI 题
A
题解:经典老套题。通过构建SAM可以让我们自由行走子串。容易发现这就是一个sg模型。对于单独一个串,抽象双方在一张拓扑图上移动棋子,简单地mex运算一下。每个串独立,最后将mex值异或起来。
G
题解:点分过不了。找性质树形DP。之后再来补做法。
H
题解:简单的二维dp。随意决策单调性一下。
3.25 2015 MIPT Workshop Open - Makoto Soejima Contest 3
3.28 Petrozavodsk Summer 2015 - Moscow IPT Contest
A
题意:给出平面里的\(N\)个点,\(Q\)次询问,每次给出一个矩阵,问矩阵里的所有点有多少种不同的横坐标和多少种不同过的列坐标。强制在线,\(N,Q \leq 50000\)。
题解;数颜色是一种很经典的不能直接维护的东西,那么我们有两个大方向。
①把数颜色问题转化掉。就比如考虑数x。一开始大力枚举每一个x坐标的所有点,假设它们的纵坐标升序排好分别是\((y_1,y_2,\dots,y_m\)。考虑它对一个询问\((y_min,y_max)\)的贡献。这是一个很经典的模型,考虑\(y_1\),它会对\(1 \leq y_{min} \leq y_1,y_1 \leq y_{max}\)的询问贡献1;再考虑\(y_2\),它对\(y_{min}\)的限制变成了\(y_1+1 \leq y_{min} \leq y_2\)。也就是说,如果固定了一个x,它对应的一组y是平面里一些矩形加操作,然后是单点询问。最后加上x的限制,我们可以对下标x建立线段树, 每一段x的区间,都保存了一些矩阵加的操作。询问时就在log个x区间里查询即可。
此模型本质是三维数点?外侧先套个线段树;然后内层的矩阵加单点求值可以通过差分变成单点加矩阵求和——这个写kdtree可能方便一些。效率是\(O(Q log^3 N)\)或者\(O(N \sqrt N log N)\)。
②暴力维护颜色,加上bitset优化。
比赛时,想到类似于①的做法。比如数y个数,对x建立类似线段树一样的结构,每一段区间维护一个对颜色y的bitset。查询时只需把log个bitset合并,然后询问bitset里\(y_min\)~\(y_max\)里有多少个1。但是这样效率是\(O(Q log N \frac{N}{64})\)的。
其实可以更快。我们直接对所有点按x升序排序。我们先采用分块的方法,每根号为一段,设\(f_{i,j}\)表示\(i~j\)这些块对应的颜色y的bitset。询问时,零碎部分直接暴力,中间的直接O(1)调用,这样就轻轻松松的\(O(Q \frac{N}{64})\)了orz……
3.30 Petrozavodsk Summer 2015 - Ivan Smirnov Contest 1
3.31 CCCC 天梯赛
3-2
题意:给出一个长度为N(\(\leq 10^6\))的字符串。最多删掉3个字符,问可能得到多少中不同的字符串。
题解:显然,删除不同个数的字符,贡献独立。
由于删除字符数量较少,给人一种可以暴力分类讨论的感觉。但事实上3的情况很复杂,我搞了好久都没搞出来。
“删除”不太经典,我们不如把题意改为保留。即至少保留\(N-3\)个点,问有多少种不同的字符串。
我们设\(f_{i,j}\)表示考虑了1~i这个前缀,目前保留了\(j\)个点,且\(i\)号点强制保留的方案数。很经典的转移,我们枚举上一个保留的点\(k\),那么\(f_{i,j}=\sum f_{k,j-1}\)。考虑判断合法的位置k。假设位置i的字符上一次出现的位置是\(p_i\),那么满足\(k<p_i\)的k都是不合法的(因为这些方案树都会在\(p_i\)处计算过)。这样我们得到了一个看似至少是\(O(N^2)\)的做法。事实上,因为j有范围\(j \geq i-3\),转移的k也会有范围。我们稍微改一下数组下标,复杂度就变成了\(O(del^2*N)\)了。
4.1 Petrozavodsk Summer 2015 - Yandex Cup Stage 2
D
题意:维护一个序列,支持两种操作:区间修改成一个数;询问区间内出现次数大于区间长度一半的数(没有输出-1)。\(N,Q \leq 10^5\)
题解:先思考答案数字的性质。若把查询区间划成一个一个段,且我们已经求出每一段里出现次数最多的数字\(p_i\):那么答案数字必然是\(p_i\)中的一个(如果存在的话)。用反证法可以轻松证明。即,该询问是“可快速合并”的结构。
所以,我们采用线段树维护这个序列。区间修改就正常地lazy标记,up时顺便维护子树里出现次数最多的数以及其出现次数。
现在问题来了:在up的时候,我们需要知道左右两个子区间的“候选数字”\(L_p\)和\(R_p\)分别在当前区间内出现的次数。
数颜色是很困难的一件事,我们只能对每一种颜色开一个数据结构维护。为了实现方便,我采用了动态开点的线段树>_<。也就是说,对于每一段颜色\((l,r,v)\),我们会在\(rt_v\)的线段树里的\((l,r)\)区间加\(1\)。这样up时就可以花log的时间求答案了。
再考虑修改对这些线段树的影响。这是个经典模型,我们可以在全局维护一棵平衡树,表示每一段连续的颜色(set即可)。区间修改时,可以暴力提取那些被包含的小区间,在它们各自颜色的\(rt\)里删掉它们的贡献,再补入一个新的大区间。
由于每一种颜色的线段树也要down,内存消耗巨大;而区间在+1后可能会被撤销。所以我们可以每次对=0的节点回收内存,收效很不错。
F
题意:给出地球上\(A,B,C,D\)四个点的经纬度。判断\(A-B\)的最短路径和\(C-D\)的最短路径是否有交点。
题解:总觉得这个弧线很奇怪啊,不可捉摸>_<。开始时脑补了一个很low的做法。三分线段\(C-D\),求出一个点\(x\)使得\(dist_{A,x}+dist_{B,x}\)最小。然后我们判断一下这个距离是否等于\(dist_{A,B}\)……
其实做法很简单。考虑平面OAB和平面OCD,它们的交必然是一条直线。我们求出交线,并算出它落在球面上的点。然后判断一下这个点是否在两条弧内部即可。
H
题意:问长度为N(\(N \leq 10^9\)),字符集大小无限的字符串有几种可能的kmp数组(同时要求kmp里每个数都不超过K(\(K \leq 10\))
题解:因为K很小,一个自然的思路就是:暴力最开头的kmp数组,之后的长度可以递推得到,N大就矩乘一下。
先考虑如何构造长度为M的所有可能的kmp数组。假设考虑完了前i位的next数组,现在我们决策第i+1位放的是什么。根据next数组转移规则,可能的\(next_{i+1}\)的值为:\(next_i+1,next_{next_i}+1,\dots,next^k_i+1,0\)。这里最麻烦的问题是判断合法性。假设我们想让\(next^p_i+1\)和i+1配对(字符相同),那么我们的要求是,\(next_i+1,\dots,next^{p-1}_i+1\)这些位置的字符不能和i+1(也即\(next^p_i+1\))相同。这里我采用过的判断是,对于上述这些位置继续暴力跳next,要求都不能经过\(next^p_i+1\)。从这里我们也会发现,我们需要预处理的字符串长度需要为\(K+1\)。
跑出来状态大概是3k多种?枚举每一种可能,设\(f_{i,j}\)表示到第i位,第i位的next是j的方案数。同样的做法求出转移矩阵,倍增一下即可。
4.4 XVIII Open Cup - Grand Prix of Korea
I
题意:对于一个字符串S,定义函数\(F_S=\sum w_i^2\)(其中\(w_i\)表示每一个本质不同的子串\(str_i\)的其出现次数)。给出一个长度\(\leq 10^5\)的字符串A,求其每一个前缀的F。
题意:若只有一个询问,这是一个经典问题。建出SAM后,本质不同的串都缩在了一个个的节点上。我们直接计算
$ \sum \limits_x {son_x}^2*(len_x-len_{f_x}) $
即可,其中 $ son_x $ 表示节点x的right集合的大小。
因为SAM是在线的,所以对于每一个前缀,它维护出来的SAM结构也是正确的。唯一的问题是,每次我们暴力扫描SAM里的点算答案了。
关注SAM插节点的过程,转化为LCT模型。每一个点有两个值,其中 $ num_x=len_x-len_{f_x} $ (这个节点表示的本质不同的串的个数)是常量,\(add_x\)是变量。我们要维护下列操作:①换父亲;②改某个点的num(注意这个其实是和换父亲是同步的,但只能分开维护);③从某个点开始到根路径\(add\)都加一。然后实时维护全局每一个点的$ add_x^2num_x \(的和。因为要在打lazy标记的时候快速求平方和,我们要维护LCT链上(即splay子树里)的:
\) \sum \limits_x val_x\(
\)\sum \limits_x {add_x}\(
\)\sum \limits_x {add_x}^2*{val_x}$
4.5 XVIII Open Cup - Grand Prix of Saratov
4.8 XVIII Open Cup - Grand Prix of Romania
I
题意:有一张N个点M条边的有向图。将这M条边动态加入图中,每次加入后统计图中有几个强连通分量,得到的答案构成一个长度为M的序列。问这样的序列一共有多少种可能。每次读入一个\(N(\leq 50)\)和\(Mmax\),要求求出\(1 \leq M \leq Mmax\)的所有M的答案。
题解:膜claris题解膜了好久才会……orz……
由于要求出所有答案,我们肯定要把选的边数放在dp计数的维度里。
首先做一个转化:所有可能的序列,我们都可以由这样的图构造出来:1i是一个大的SCC,i+1n都是单独一个的SCC。
现在我们要对这种图作一个序列的计数。一个很自然的想法是,我们设\(f_{i,j}\)表示选了i条边,1~j是大SCC的方案数。但是我们会发现无法转移:我们无法预料下一次j的扩大是何时,因为我们没有记录连边的信息。
然后出现了一个很帅气的做法:增设一个k表示1j这个SCC是由k个环组成的。什么意思呢?考虑我们在某种序列的要求下,用边最少的构出这个SCC的方法。大概是,先连1->2,2->3……j-1->j这些边;然后在一些点处会往回连边,使得1j成为一个合法的SCC,而k正是往回连的边的数量。看起来k的定义很鸡肋。
首先我们证明这种表示是“可dp的”。对于一组相同的\((i,j)\)和不同的\(k\),\(f_{i,j,k}\)所代表的序列是不可能相同的。这个显然,因为一个序列发生改变的点有k个,k不同自然序列必然不同;然后,满足状态\(f_{i,j}\)的序列,都是可以规约到一个k的(会被一个k计数到)。
我们还会发现,记录了这个k后就可以转移了!考虑\(f_{i,j,k}\)的转移。如果此次不合并SCC,那么相当于加了一条“废边”(注意,这并不表示这条边一定无效,而相当于是一条“任意边”),直接转移到\(f_{i+1,j,k}\)即可;否则,我们枚举合并了\(j+1~l\)这些点。那么我们本次需要的边的数量是:\(l-(j+1)\)+1(新增的一条回去的环边)。我们只需看一看,这个dp状态还剩下多少条“任意边”可以供我们使用,具体是\((i+1)-k-(j-1)\)。也就是说,如果这个值是不小于我们本次转移需要的边数的,我们相当于可以在之前加“任意边”的时候,加的是本次要求的边;这样就把\(f_{i,j,k}\)转移到了\(f_{i+1,l,k+1}\)去了。
这个dp直接做事\(O(N^2*N*N*N)\)的,加入一个前缀和优化就是\(O(N^4)\)了。
4.11 Petrozavodsk Summer 2017 - Warsaw U Contest
A
题意:动态地往N\((\leq 500)\)个点图中加入\(M(\leq 10^6)\)条边\((x,y,color)\),每次询问有多少个点对\((u,v)\),满足对于任意一种颜色c\((1 \leq c \leq d \leq 200)\),u可以只通过c的边到达v。12s。
题解:这题还是比较帅气的。一种暴力做法是\(N^2*d\)的,对于每一种颜色维护一张并查集,当一条边连通两个块时,暴力两两扫描两个块,把\(f_{i,j}++\),如果一个二元组的f等于d了,就在此时变得合法了。
该算法无法继续优化。最大的瓶颈是:如何快速判定新合法的一组点对?有一个很棒的idea是hash。对于一个点,我们把它在每种颜色的并查集根拎出来。那么两个点构成合法二元组,当且仅当这些根一一对应相等。那么我们可以给每一个根都随机一个key,然后当两个点各自key的异或值ret相等,我们就认为其合法。这样算法框架就出来了。启发式地暴力维护连通块,每次扫描小的那一块,修改里面的点的ret,并开一个map统计一下答案该变量。如果把map换成hash,复杂度就是\(O(M+DNlogN)\)。
J
题意:有\(M(\leq 100)\)台机器可以同时执行任务。总共有\(N(\leq 100)\)个任务,每个任务有一个最早可以开始做的时间\(st_i\),最晚截止时间\(ed_i (\leq 10^6)\),完成所需时间\(t_i\)。可以在任意时刻暂时取消执行某个任务(换上别的任务),过一会再继续执行原来的任务。问是否存在一种完成所有任务的方法。
题解:首先,肯定是把任务在时间轴上按\(st_i\)排序,每次进来一些新的任务。脑补了一个按“最迟必须开始时间”排序的策略(\(ed_i-rest_i\)),每次选前m个做。可惜的是,这个东西变化较大,好像做到与T无关的离散处理?
换一种思路,用网络流。一个暴力的想法是,左侧一排任务,右侧开\(T\)个时间点,直接连边即可。注意到,“关键”的时间点是\(O(N)\)的,所以右侧的时间点不需要全部开出来。在关键点之间的点可以缩成一个点,流量合并。直接流一流即可。
4.13 XVIII Open Cup - Grand Prix of Urals
D
题意:有多少个长度为\(N(\leq 10^6)\)的回文十进制数字串,使得其奇数位和偶数位上的和相同。
题解:N是奇数的时候比较麻烦。一种很自然但很naive的想法是,我们枚举除中间点外奇数位上的和S,那么偶数位上的和是S+w(w是一个小于10的偶数)。那么我们要支持O(1)计算长度为m,和为S的十进制数字串的个数。
注意到我们把问题一般化了,注意到S之间的差只有0,2,4,6,8这些,我们不必去枚举总和,而是要直接focus这个差值。
考虑从生成函数的角度去做这个问题。我们可以设奇数位上每一位的生成函数为:\(x^0+x^1+\dots+x^9\);偶数位上的为:\(x^0+x^{-1}+\dots+x^{-9}\)。对这些求个连乘,答案就是指数为\(0,2,4,6,8\)的那些x前面的系数和。然后左右两个式子我们都可以用等比数列和二项式展开化简,最后变成两个多项式的乘积。扫一扫目标点的答案即可。
E
题意:章鱼图:有且只有一个环,且环上每个点最多延伸出去一条链。给出一张由一个合法章鱼图加上了一条边的图,判断加上的是哪一条边。
题解:其实是比较无趣的分类大讨论。Generally有四种情况:链x-链x;链x-链y;链x-环;环-环。
首先我们可以用tarjan预处理出没条边是否是环边。考虑把那些环边抽出来组成一幅新图。对于Case3和4,答案边的某个端点一定是新图里度数>=3的点,我们暴力check这些点即可(即每次删掉和这个点相连的其中一条边,检验原图是否变成了一幅章鱼图)。对于Case1,新图会是两个不连通的环,那么我们找到连接它们的两个端点check一些即可。
比赛时没想清楚Case2的情况。它的新图可以抽象成有两个度数为3的点,它们之间有3条路径连接。我们依次枚举新图里每一条路径的每一条边,这条边能成为答案的充要条件是:它所在的路径上除它的端点之外的所有点,在原图里没有别的支链。
F
题意:要探测一个长度为 \(N(\leq 5000)\) 的排列P(\(0..N-1\))。每次可以给出三个数\((a,b,c)\),返回\(p^{-1}((p(a)*p(b)+p(c)) \mod n)\)的值。其中\(p(a)\)表示排列里第\(a\)个数是什么,\(p^{-1}(a)\)表示\(a\)在排列里是第几个。要求询问次数不能超过12512。
题解:首先我们发现,最关键的是求出\(one\)(1所在的位置)。这样的话,我们每次询问\((one,i,one)\),就可以知道\(i+1\)的位置了。
把括号里的式子搞成1还是比较难的。因为有mod n,我们考虑先搞成0,求出0的位置\(zero\)。具体的,我们只要枚举所有的i,迭代\(x=(x,i,x)\),最后的x就是\(zero\)。因为迭代了n轮求出的值相当于是\(p^{-1}(p(x)*(p(0)+1)*(p(1)+1)*\dots*(p(n-1)+1))\),它对n取模必然是0,即最后肯定返回了0的位置。
现在考虑知道了\(zero\)求\(one\)。我们设一个集合S表示1可能的位置(初始时S里放入n-1个位置)。每次我们随机找出两个数\(x\)和\(y\),做一遍\((x,y,zero)\),如果返回不为x,y就必然不是1;反之同理。这样每次至少去掉一个数,且很大概率去掉两个数。这样总询问次数是\(2.5n+delta\)。
4.15 XVIII Open Cup - Grand Prix of Eurasia
E
题意:有按顺序的\(M\)个格子,每一个格子里或者是空,或者是一个pair\((x,y)\)。保证初始时,对于相同的\(x\),\((x,y)\)必然是连续的一块且\(y\)必然递增。每轮操作可以选取一个非空的格子,将其中的pair取出来,塞入另一个指定的格子;如果那个格子里有pair,就再取出该pair,重复此操作……直到最后塞入一个空的格子。每轮代价是操作涉及到的pair的个数。现在要进行若干轮操作,使得最终二元组递增排列(无视空格子),求最小代价和。
4.18 XVII Open Cup - Grand Prix of Tatarstan (Kononov Cup 2017)
C 经典的倍增NTT。因为修改只有30次,每次修改后最多只有60段颜色。对于每一段颜色倍增卷积即可。
K 直接用数据结构模拟此过程即可。涉及到一个动态改一个点的数值,动态查里一个点最近的大于等于它的位置。这个可以用二分+线段树很方便的处理。
E
题意:在 \(K(K \leq N)\) 进制下考虑问题。要求构造一些长度为2的数字串,使得对于所有 \(N(2 \leq N \leq 100)\) 位的数字串,它至少有一个子序列被构造过。求最少需要构造的串的数量。
I
题意:给出 \(N(\leq 200)\) 个串\(S_i\),总长\(\leq 2*10^5\)。初始时,可以把每一个串都进行若干步循环移位的操作,得到\(S'_i\)。然后求一个最小的k,使得\(P(S'_i,k)\)两两不相同。
4.20 XVII Open Cup - Petrozavodsk Summer 2017 - Moscow IPT Contest
B
题意:定义一个数列A的最大划分是 \(f(A)=max\{Xor_{1..j}+Xor_{j+1..n}\}\)。现在给出一个长度为 \(N\) 的序列A,求其每一个前缀的最大划分。\(N,数字大小 \leq 10^6\)
题解:显然先做一个前缀xor。对于一个询问\(A_{1..i}\),最大划分即为 \(f(A)=max\{Sum_j+(Sum_i \oplus Sum_j)\}\)。现在我们从高到低讨论\(Sum_i\)里的每一位。如果某一个bit是1,那么j无论怎么取贡献都一样,因为相加的两者必然一个是1,一个是0。只有当某一个bit是0的时候,可能有\((0,0)\)和\((1,1)\)两种可能;而且我们会发现,如果能取到\((1,1)\),一定比取\((0,0\)优秀。现在算法框架出来了:枚举\(Sum_i\)的每一个0的位置,然后去check“存不存在一个\(j\),使得\(Sum_j\)某几个特定的位为1。
如果是先全部插入最后在多次询问,可以用n维前缀和在\(O(n*2^n)\)里算出来。可惜这里还有动态插入。
不过此题无需求S超集的和,只要求是否存在一个S的超集之前被插入过。那么我们可以用均摊来暴力。每次插入一个\(Sum_j\)的时候,我们枚举它的所有子集,暴力把它们的ans都置为1。而每当bfs一个状态ans已经是1的时候就不需要继续做了。复杂度显然是\(O(n*2^n)\)。
H
题意:有一个\(N*M\)的01矩阵。每一轮先找到目前是1的所有位置,然后依次对这些位置做一遍change(change一个位置\((x,y)\)时,所有横坐标为x或纵坐标为y的点都执行01翻转;注意\((x,y)\)这个位置只执行一次)。每轮结束后,如果矩阵中依旧有1,继续下一轮操作。问把矩阵变成全0一共做了几遍change(而不是几轮),或输出永远也不会停止。
初始时读入\(K\)个矩形,所有被奇数个矩形覆盖的地方视为1,否则视为0。\((N,M,K \leq 10^5)\)
题解:可以证明(也可以打表),轮数最多两次。即两轮过后如果仍然存在1,则无解。
考虑如何硬性模拟这个过程。显然,把每一个用来异或的矩形拆成两条扫描线。我们按列枚举过去,暴力用bitset维护出当前列的01状态\(cur\)。那么如何判断第一轮过后这一列的情况?我们发现,我们还要事先算出每一列状态\(cur_j\)的异或和\(Sum_{cur}\)(表示每一行是否会遭到这一行带来的翻转影响)。那么\(cur_i\)的会被异或上行的贡献 \(Sum_{cur_i}\),会异或上列的贡献(如果cur里有奇数个1);另外,如果\(cur_i\)是1,它本身会在行和列影响里算了两边:所以还要再异或上自己。一通操作后即可求出每一列新状态\(cur'\)。如法炮制可以求出第二轮结束后的每一列状态\(cur''\)。
裸模拟的话需要卡一卡常数才能过。把代码写出来后,观察各种异或的操作,发现很多都会抵消:其实我们只需求出初始时每一列的状态里1的个数,以及每一列状态的异或和\(Sum_{cur}\)。而这些都可以直接用维护01的线段树来完成。这样复杂度就降成了\(O(N \log N)\)
4.22 Petrozavodsk Summer 2017 - JOI TST 2012 Selection
E
题意:有一个 \(N*N(N \leq 1000)\) 的方形矩阵。有 \(Q(Q \leq 2000)\) 个操作,每次给出一个正方形,要求把里面的值逆时针旋转90°。输出最后矩阵的样子。
题解:此题算是今年ZOJ新手上路某题的弱化版>_<。
为了方便,可以在正方形矩阵外面再加一圈点;值得注意的是,我们维护的是边(一个点 \((x,y)\) 连出去的四条边)。
每一条边上都会有一个旋转标记 \(rev\)(注意,这是永久标记!!!)。当我们要去find一个固定位置的点时,我们从任意某个不变的起点出发(即外围的某个点),每经过一条边,都把当前累计的\(Sum_{rev}\)并上该边的\(rev\)。每次我们想向上下左右一个方向d走的时候,d要经过\(Sum_{rev}\)的调整。我们需要的做到的是,对于每一个操作,都实时维护一些边,使得从不变起点沿任意一条路径,都能确实地“定位”一个点 \((x,y)\) 的id。
对于一次旋转操作,我们暴力找到目前正方形四周的那些点S以及它们外围一圈的点T(顺便得到了它们的\(Sum_{rev}\)),并先根据旋转90°将它们放到新的位置上。现在的问题是:里面的点本质是没有转的,所以每当我们从T跨越到S时,要求 \(Sum_{rev}\) 发生一些变化,接着在这个矩阵里走的话就能重定向成实际的方向。
然后,为了保证结构正确,对于所有S->T和T->S的边,我们要重构它们的 \(rev\) ;即计算出它应该打什么标记,使得从 \(i\) 走到 \(j\) 时,\(Sum_{rev_i}\) 会变成 \(Sum_{rev_k}\) 。
4.25 XVIII Open Cup - Grand Prix of Ukraine
H
题意:
题解: