训练记录PART1 2017.11.05~2018.01.08

友情提醒:大部分题选自opentrains,以后有训练需要的同学慎重查看。

11/05

bestcoder #93 C
  等价于给出很多环,等概率选择N个点,收益为出现过点的环的环长lcm。不同的环只有 \(\sqrt {26}=6\) 个,用\(f_S\)表示点出现在状态为S的那些环里的选取总数,DP一下即可。
bestcoder #93 D
  考虑meet in the middle。推一下式子,设左侧选的数和为\(A_{left}t\),两两乘积之和为\(B_{left}\),那么满足\(B_{left}+B_{right}+A_{left}*A_{right}>=0\)的方案即为合法方案。把左侧(A,B)看成常数,就是平面里一条直线,询问一下右侧有多少点符合在这条直线一侧即可。

   给出一个平面点集,每次询问一条直线一侧有多少个点,可以用kdtree实现当区域里4个点都不合法就跳出;4个点都合法就直接统计一下答案。

bestcoder #92 C
  显然,2和3的相对顺序不会发生变换,每次必然是2和3的交换。设\(f(i,j,k)\)表示决策完第i个数,目前选了j个"233",且目前数列后面还多了k个3(注意k可以是负数,表示还需要添-k个3才能成功拼出j组)。如果下一个数字是3,那么直接用k+1更新答案。否则,决策这个2是否算在最优答案里。无论算不算,还要枚举一个u表示之后还延续u个3。这样效率是\(O(N^4)\)的,但是实测跑的很快。

  题解提供了\(O(N^3)\)的做法。交换本质是对2序列和3序列进行归并排序。设\(f[i][j][k][sta]\)表示决策到前i个2,前j个3,目前交换了k次,且状态为sta时的最多组数。规定sta=1表示前一个放的是2,缺1个3;sta=2表示缺2个3,;sta=1表示不缺3。\(O(1)\)转移一下即可。

bestcoder #92 D
  依次考虑每一个可行区间。一个游戏会覆盖中间连续的一段区间,以及某个区间的右半段和某个区间的左半段。离线往区间里放游戏。完全覆盖区间的游戏只需取一个d最小的即可。对于在区间其前半段的游戏,维护一个d递增,前缀递增的数列;后半段也类似。然后根据两侧哪个小,像归并排序一般贪心取。剩下的再用完整覆盖的d最小的游戏填充即可。

bestcoder #91 C
  线段树维护矩阵。

bestcoder #90 C
   感觉很复杂。用线段树实时维护颜色信息、段数,再对于每一种颜色开一个set记录它的每一个区间。如果替换的目标颜色之前没有过,就稍微判一判,不理它;否则暴力把被替换的颜色合并进新颜色的set里。这里还要启发式一下,效率\(O(N \log^2 N)\)

  题解果然比较简单。首先可以用树状数组记录每一个颜色起始处的位置,然后在区间里查起始点个数就是颜色段数。替换颜色的话,直接开一堆vector,启发式合并(小的并到大的里,不需要位置有序)就好了……我在想什么……

51nod #30 C 看上去就是个集合DP。但是每次无法快速枚举一个环。即使预处理出某个集合有几种方式能凑成一个环,最终DP的时候也要\(O(3^N)\),不会做……

  题解: 注意将图上的环和二分图完美匹配联系在一起!
  这个模型已经见过不止一次了,我还是没有想到……一个拆成不相交简单环的方案,是一一对应于一个完美匹配的方案。所以我们可以设\(F_S\)表示左侧1~bit(S)这些点和右侧S这些点匹配的方案数。效率\(O(N*2^N)\)

11/06

CC NOV17 CSUBQ
  采用容斥原理。设小于L的数的权值是0,[L,R]的数的权值是1,大于R的数的权值是2。那么答案就是“不包含2的区间个数”-“不包含1且不包含0的区间个数”。对于这个,直接线段树维护左连续右连续等东西即可。

CC NOV17 SEGPROD
  由于没有逆元,直接维护必然是带log的。考虑拆分这个P,拆成\(p_i^{k_i}\)的形式,分别做一遍答案,最后再CRT合起来即可。考虑如何快速求区间乘积模\(p^k\)的答案。我们先抠掉p的倍数做一遍前缀积,同时维护含p的因子数的前缀和。每次询问,先看看p因子有没有超过k,没有的话再用前缀积相除即可(这里只能用exgcd求逆元)。由于相除的exgcd是log的,效率爆炸。我们考虑P中最大的\(p^k\)。除了它的\(p^k\)必然是小于 \(\sqrt {P}=6\) 的,我们可以先预处理每一个值的逆元。这样,每次只需对最大的\(p^k\)求一遍exgcd,效率就是\(O( \log N + \log N)\)的。其实常数瓶颈还是在exgcd上,机智的发现,不同的L只有N个,这个也可以之前预处理,这样就能卡过了。
  据说有优化取模+zkw强艹的做法,难难。

CC NOV17 LVGFT
  直接点分,然后考虑经过分治中心rt的影响。如果子树A里的x能走到子树B里的y,存在两种可能。(1)在询问它时,x到根rt路径的某个点已经变成银行了。(2)在询问它时,y到根rt路径上的某个点已经变成银行了。 对于(1),我们只需按时间过一遍,每次建银行的时候暴力往子树打标记(均摊正确),询问时,如果当前点x有标记,就看看除了x子树所在子树外,整棵树的最大权值和次大权值。对于(2),也只需按时间过一遍,每次建银行的时候暴力跑向子树,把子树的权值放进我们考虑的范围内;询问的时候,看看除了当前点x所在子树外,目前在我们考虑过的最大权值和次大权值。
  如何求“除了当前子树”的最大和次大权值呢?其实只需维护全局的前4大值,然后保证每棵子树的贡献 $ \leq 2$即可。

11/07,11/08

**CC **

11/09

bestcoder #89 C
  一直觉得合法翻转状态有\(2^{50}\)种,根本不会做。
  发现看错题了,原来是翻转子树里的点啊!那从上往下考虑,就会发现合法翻转只有1种可能。
  直接设\(f_i\)表示翻了i个正确的期望步数。直接暴力转移高斯消元即可。

bestcoder #89 D 待补。

bestcoder #88 C
  CCPC2017杭州几乎出了一样的原题……后悔没来做。
  我们先尝试去解决“强制选了根能选到的集合”。
  设\(f_x\)表示强制选了x,且dfs序 \(\leq dfsR_x\) 的这些点中选了若干能选到的权值(bitset)。
  来到\(x\)后,设它的某个儿子是\(y\),我们先使\(f_{y,v}=f_{y \oplus a_x}\)。每次做完\(x\)后,我们再用\(f_x+f_y\)去更新\(f_x\)
  最后还有可能是没有选根;我们去掉根后就变成了一些子树,这就是点分的模型。再套一个点分即可。
   这个本质是按DFS序进行DP

题解里还附上了一种做法:设\(f_{x,k}\)表示子树x里必须选x,能拼出k的方案数。每次转移是一个FWT形式,优化一下即可。

bestcoder #88 D
  对于L~R这段点,常规操作是用线段树优化最短路连边。但是\((x+dx*i,y+dy*i)\)似乎不能用什么姿势优化连边……

  题解的做法真是强大!我们把连的这\(e\)条边视作点,在上面做dijkstra;而原图中的点,在新图中其实是一些起到辅助作用的边。
容易发现,新图是有点权、但没有边权的图。它具有性质:每次用一条边(第一次)松弛到y的时候,到y的最短距离已经被确定。 这个性质为后面的均摊保证了正确性。
  我们每次在小根堆中取出x后,就暴力去查找边x本来能到达哪些点。容易发现,一个点被查找过一次后,一定不会再用到了,所以每次要查找一个矩阵里还没有被删掉的点,处理完它的贡献后删掉它再删掉它。UPD:对于每一行独立做。 按dy分块,小的之前直接暴力用链表,该删就删;大的暴力跳即可 假设我们找到了矩阵里的\(k\),我们只要再暴力地找到它本来连向原图中的哪些边\(y\)。由上述性质,边\(y\)必然还没有被松弛过(也即不在堆中);最后我们把\(y\)更新并放入堆中,同时删掉\(y\),让以后的点找不到它。这里只需以原图的点为下标维护一棵线段树,每一个区间维护能到哪些边。一条边被删掉后只需标记一下,点\(k\)在寻找的时候若边被标记过,则删掉找下一个。这样均摊是正确的。

11/11

Atcoder #85 F
  海明距离最小,即相同位置最多。设\(f_{x,y}\)表示前\(x\)个点已经确定,\(x+1 \dots y\)这些点必须是1(即必须有条线段的R正好是y),\(y+1 \dots n\)这些点还没考虑过的最多相同位置。 N很大的时候,二维DP往往一维放在线段树下标上,每次推进另一维并更新DP数值。 考虑从\(f_x\)\(f_{x+1}\)的转移。注意到\(f_{x,y} \rightarrow f_{x+1,y}\)可以直接继承。先假设\(x+1\)上没有线段覆盖,我们用\(f_{x,x}+[b_{x+1}==0]\)来更新\(f_{x+1,x+1}\)。然后假设\(x+1\)上有线段覆盖,那么枚举所有\(l_i=x+1\)的线段(按照这种顺序,\(l_i<=x\)的线段都被决策过了),用\(\max {f_{x+1,y}+sumb_{r_i}-sumb_y}\)来更新\(f_{x+1,r_i}\)。由以上操作,对于一个\(x\),维护一棵\(f_{x,y}-sum_y\)的线段树,然后就变成了区间求max和单点修改的操作了。

2015 Hefei H
  首先,由“回文树模板节点数只开了N”事实,得到结论:全a串拥有最多的本质不同的子串。然后根据K分类讨论。
K>=3的时候,注意到在一个串后面添加bcabcabca……后,只会有a,b,c这三个本质不同的子串。我们可以在前面一直添a,等到差不多M了就放bcabca……。在N,M小的时候要特判一些细节。
  K=2的时候比较麻烦。根据CC NOV17某题的结论,N足够大的时候,两种字符构成的长度为N的串中,最大回文子串最小长度是4,且其结构为abbaab abbaab……。数一数,无论N多大,它都只有8个本质不同的子串。有一个更有趣的性质是,每往前面加一个a,正好能多出一个本质不同的回文子串。所以我们可以放M-8个a,剩下循环几次就好了。注意N小的时候这个结论是不成立的,跑一个爆搜判一判即可。

11/12

2017 Shenyang C
  据说是原题?我的做法可以简化成:每次枚举解里的最低点,抛弃它下面的点后,对所有点关于这个点极角排序(这样就能保证找到的凸包的但在序列里下标递增)。我们在判断合法性的时候,是要知道最后一条边是什么的,所以直接设\(f_{i,j}\)表示最后一个点是\(i\),之前一个点是\(j\)这个状态目前的最大面积(包围区域的三角形面积总和)。每次枚举一个新的点\(k\),判一判合法性,再加一个新的三角形面积进去。这样是\(O(N^4)\)
  据说还有\(O(N^3)\)的做法,以后再补吧。

11/15

XVII Open Cup - Grand Prix of Siberia D
  里侧连和外侧连是两个完全相同的结构。然后,某一侧有冲突,就是产生了逆序对。所以问题转化成,给你一个排列,每一个点有一个代价:将其拆成两个不相交的不降子序列,使得在A集合里的点代价和最小/大。显然,最长下降子序列长度>=3就无解。如果可以\(O(N^2)\)的话,直接对逆序对暴力连边,然后在每一个连通的二分图里奇偶染色,挑一个优的放在A集合里即可。我采用的是暴力连边的方法。假想对那张二分图BFS:每次取出一个还没被删掉的点,每次在它前面找到所有大于它的,在它后面找到所有小于它的;暴力连上边,删掉前后的那些点;再对那些点重复操作。用线段树维护,均摊\(O(N \log N)\)

XVII Open Cup - Grand Prix of Siberia F
  首先想到,只要对%M的每一个值开一个点,就可以构造出一个符合要求的自动机。因为要点数最小,很自然地想到,对于\(x\)\(y\),如果\(x*B%M\)\(y*B%M\)相同,那么它们所有出边均相同,可以将它们缩成一个点。事实上,缩了之后还可以再缩!后来缩就只能每次哈希出边,把出边一样的那些点统统缩起来。迭代几次就好了,SF哥哥说不会超过\(O(\log N)\)次。

11/16

2016 ICPC Beijing I
  如果暴力维护\(x^k\)前面的系数和的话,加上转移的效率是\(O(N*m^2)\),完全过不了;即使加一个FFT也没有卵用。
   考虑斯特林反演:\(x^k=\sum \limits_{i=0}^k S_{k,i}*x^{[i]}\)。由于组合数有良好的递推性质,一般写成\(x^k=\sum \limits_{i=0}^k S_{k,i}*{C_k^i}*i!\)。对于所有到i结束的那些后缀和\(x_1,x_2,\dots,x_i\),我们用\(f_k\)表示\(\sum \limits_{i} C_{x_i}^k\)\(f_k\)可以直接通过类似组合数的转移。

11/18

2016 ICPC beijing

11/22

CF Moscow 2017 I
  先直接给出做法:若维度是m,设m个未知数\(x^1 \dots x^m\)。列出方程组\(v_{i,1}*x_1 \oplus v_{i,2}*x_2 \oplus \dots \oplus v_{i,m}*x_m=1\)。如果至少存在一组合法解,则是二分图,否则不是。
证明:
  ①合法解->是二分图。既然我们知道了一组解,我们关注\(x_i=1\)的那些维度。对于空间里的某个向量,我们考察它在这些维度的坐标的异或和。注意到,无论用哪个给定的向量一次,必然会使异或和改变。所以,我们可以直接指出一种染色方案:所有这些维度异或和是0的染白色,异或和是1的染黑色。
  ②无解->不是二分图。考虑m维上的自然基。\(x_i\)可以看成是“由目前已知的向量拼出第i个自然基需要向量个数的奇偶性”(显然奇偶不可能都存在,否则直接无解了)。那么,每一组方程实际的含义是,要拼出\(v_i\)需要步数的奇偶性:任意一个都要被奇数个向量被拼出。那么,如果无解,说明有个自然基要求既能被奇数个向量拼出,又能被偶数个向量拼出。显然这是无解的。

11/24

CF edu31 F
  将距离限制转化成 \(dis_y \leq dis_x+k\),子树限制转化成DFS序。现在问题变成,在一个序列里,每次给出两个数\(v1,v2\),求\(L_{v1}\)~\(R_{v1}\)这些数里,满足\(deep_x \leq v2\)\(x\)中最小的\(a_x\)。虽然是矩阵询问,但有一侧是无限的。如果考虑离线的话,可以按deep从小到大加入点,每次询问已经加入的那些点里的最小值。强制在线的话,只需建一棵主席树出来即可。效率\(O(M \log N)\)

???
  题意是:给出一个\(N=40\)的无向图。要给每一个点分配一个非负实数,总和为1。一条边的权值是两端点权乘积。求一个最优分配方案使边权和最大。
  仔细思考一下,解的点集一定是一个最大团(可以用调整法证明)。团里分配必然全一样。

11/25

玲珑杯#21 B
  似乎要有一波转化?悄咪咪地偷看了一下题解。
  对于两个有关系的点\((x,y)\),发现它们是否是逆序对取决于较大的数的符号。所以我们可以将所有二元关系都在较大处算贡献。
  分别统计\(x\)的祖先和子树里小于\(x\)的数字个数,然后做一遍背包即可。

玲珑杯#21 E
  感觉挺裸的。考虑计算出所有\(f_x\)。点分,考虑子树之间的贡献。对于某个子树里的点\(x\),设其到分治中心的距离是\(L\),它收到的收益是\(num_0*a_L+num_1*a_{L+1}……\)。再考虑\(L+1\)等,发现将一个数组反一下就是一个卷积。用FFT优化一下即可。

玲珑杯#20 A
  看上去不能用数据结构直接维护?既然这样,那就用莫队套一套吧,总体效率就是\(O(M \sqrt N \log log N)\)。可能过不去?翻了翻题解,它还对\(v\)分块了。大于1000的质因子最多只有1个,这样还是用莫队维护;小于1000的质因子只有168个,单独对它们开前缀和预处理,每次询问循环一遍问一问。效率就是\(O(M \sqrt N + 168(N+M) )\)

玲珑杯#20 B
  平均数一定了,那么就直接DP好了。式子推一推,每一层由上一层推出来,是一个斜率优化形式。直接这样是\(O(NM)\)的。题解做法暂时没看懂,以后来补。

玲珑杯#20 C
  又涨姿势了!转化后的题意是:每次给\(L,R\),对于区间内每一个不同的数\(x\),设其出现了\(y\)次,其贡献是\(x*(2^{len}-2^y\);每次求一个区间的值,模一个每次都给定的数。
  模数每次都会变化?这应该怎么做呢???这个\(x*2^y\),根本毫无头绪。
  事实上,有一个经典结论是:一段区间数字出现的不同次数最多只有\(O(\sqrt N)\)种。
  考虑莫队,对于出现次数相同数字合并计算。因为只有根号种,每次暴力乘\(2^k\)即可。看起来还要一个快速幂的log,效率应该是\(O(N \sqrt N log N)\)

11/28##

XVII Open Cup - Grand Prix of Two Capitals H
  如果去掉那个or(即强制X要属于至少某一个集合且Y不属于),就是一个普通的\(O(2^M)\)的容斥。但是将答案乘2后,要减去那种(X,Y)和(Y,X)同时能属于和不属于某个集合的 集合对数量。这个好像不怎么能做啊。
  其实,可以先\(2^M\)枚举参与限制的那些集合\(A_i\),不管它们是正着还是反着的,他们对答案贡献的系数就是和原来基本容斥一样。然后再在那些集合里\(2^k\)枚举正着的集合,剩下的就是反着的,计算一下贡献即可。效率是\(O(3^M*100/64)\)的,加点剪枝就过了。

11/29

玲珑杯#20 G
  将问题转化成了求 \(\sum \limits_{i=0}^{\lfloor \frac{n}{k} \rfloor} C_n^{ki}\),然后就入歧途了>_<。
  考虑直接按照原题意DP,设\(f_{i,j}\)表示考虑了前i本书,选出的书数量\(mod k=j\)的方案数。
  N特别大,要快速处理转移矩阵的倍增。观察发现,转移矩阵是一个循环矩阵
  容易发现,只要求出循环矩阵的第一行,就得到了全部(因为循环矩阵自乘还是循环矩阵)。
  再观察,发现第一行本质是原矩阵第一行卷积得到的。所以每次倍增的时候,只需把原来的数组卷积一下,效率就是\(O(K \log K \log N)\)
  当K很大且是2的幂次的时候,就不需要每次DFT来回了。可以直接保留DFT后的数组,每次卷积直接自乘即可。因为\(K\)位数组自乘保留K位后,会循环累加,当\(K\)是2的幂次时,刚好符合我们要求的东西。
   循环矩阵可以用倍增NTT来算

12/06

ASC 42 J
  这题好奇妙呀!裸的\(O(\frac{NM}{64})\)的做法是会被卡内存的。比赛时我脑补了一下,觉得不存在利用题目性质的方法,要大力卡内存。通过观察两个最极端的例子(菊花树和链),分别想到两个姿势:①一个点能到的点可能会很少。我们可以动态给他分配bitset,只分配给他块里有值的那些未知的bitset,并用链表串起来。②当一个点已经不能更新别的点的时候(它的前驱都被做完了),就回收它占用的所有内存。 看上去很难卡这个做法呢!我再取了前100个最有可能成为答案的暴力做一遍,同时加一个“某时超过内存总限制就直接输出当前最优解”,稳健地过了。
  观察标程,竟然只是把每一个点分组!比如所有点被分成了K组;每次跑一遍整个图,计算每一个点对于某一组的到达情况。这样空间显然减小了K倍,而时间效率是\(O(M*K*\frac{N/K}{64})\),看上去没变呢QAQ!挺神奇的!

12/09

EOJ 3440
  这道题的idea挺有趣的,虽然做法比较无聊QAQ。假设我们知道a要计算p,那么对于一对树上的父子\((x,y)\)\(p_x=p_y+sum_y-(sum_1-sum_y)\)。我们发现,只要知道了\(sum_1\),就能表示出整棵树每一个点的sum。假设\(sum_1\)是未知数,最后根据等式\(p_1=\sum \limits_{k=2}^n sum_k\)列出方程。解出\(sum_1\)后再跑一遍就可以还原答案了。

XVIII Open Cup Spb E
  这题感觉挺经典的,就是直接对它 连分数展开(对于一个实数\(0 \le x \le 1\),设\(a=\lfloor \frac{1}{x} \rfloor\),然后\(x'=\frac{1}{x}-a\)),展开到一定精度即可。由于保证解唯一,所以展开到最大的范围内的\((p,q)\)时停止(注意展开只会越来越精确),或是展到p/q等于答案时停止,都是合法的。求答案的时候不一定要用展开的逆形式去求。设第0次展开的答案是\(\frac{p_0}{q_0}\),第1次是\(\frac{p_1}{q_1}\),用数学归纳法易证,第n次\(\frac{p_n}{q_n}=\frac{p_{n-1}*a+p_{n-2}}{q_{n-1}*a+q_{n-2}}\)

12/10

2014 ICPC Asia Shanghai A
  广义的生成树定理。打了打表,如果一条边边权是d,那么度数矩阵和邻接矩阵操作的都是d;这样搞出来的答案是每一种生成树边的乘积和。此题中,将每条边看成多项式:“虫洞边”是\(x\),“普通边“是\(1\),两者都可以是\(x+1\)。算出一棵生成树多项式的乘积,其\(x^n\)前的系数就是用了\(n\)条虫洞边的方案数。广义上来说,直接对多项式套maxtrix-tree定理即可。事实上,我们可以取一些x的具体数值,转化成普通生成树计数,然后把结果插值插回一个多项式。

12/11

牛客网 浙工大2017程序设计热身赛 F
  题目很有意思。我手动玩几次发现,最终答案好像全都\(\leq 2\)?(除了初始的颜色全都一样的情况)
  区间DP的思路很明显,设\(f_{i,j,k}\)表示i~j这一段最后只消成颜色k,最少还留下几个。从\(f_{i+1,j}\)\(f_{i,j-1}\)转移。(正确性不会证,手画感觉是对的)
  继续深入探究,发现很容易消到最后的状态>_<。如果我们每次随意消一组,是存在反例的,比如bbac。
我猜了一个结论:对于一组目前可以消的(x,y),如果消完后和左右颜色一样,我就尽量先不要消(除非只有这种能消了)。这样就过了Orz。

Atcoder #86D
  标准做法很简单。如果所有数同号,扫一遍就可以出答案了。此题中,可以先找到一个绝对值最大的,把它加给别的所有点,这样所有点都同号了……步数是\(2*N-1\)
  我想麻烦了>_<不过我的做法每次的\((x,y)\)都是相邻的呢!
  先考虑两个逆序的数\((A,B)\)。我们可以找到一个绝对值大的,把它的两倍加到另一个上。可以证明,现在两个数必然不降。
  序列上可能会出些问题。我们先从左向右扫过去,每次遇到逆序组\((A,B)\)时:

  • |A|大。那么直接按照上述方法维护。
  • |B|大。此时我们不能A+=B(因为会破坏之前的结构)。此时,我直接恢复成原来的数组(删除之前的所有操作),以B为基准点。然后向前循环,每次 前一个数+=后一个数*2。
      每次做完一个前缀的时候,我们都能保证前缀是不降的。步数大概是\(2*(N-1)\)

12/13

NWERC 2017 F
  脑补一下,每次找到在区间里找到一个与别的数都互质的数作为根,然后左右分治下去,复杂度是对的。
  但是分治区间的长度可能不平衡。 注意到有一个两边夹的经典方法,即依次检验\(L,R,L+1,R-1 \dots\)
  如果每次验证都是O(1)的,这个复杂度就是\(T(N)=T(x)+T(N-x)+O(x)\),最终是\(O(N \log N)\)的。
  现在我们只需解决,区间里的一个数x是否与别的数都互质。
  这个可以转化为:x左(右)侧第一个与它不互质的数在哪里。
  枚举x的所有质数p,找到左(右)侧最近的也有p的数即可。
  这样总效率是优秀的\(O(N \log N)\)

牛客网 浙工大2017程序设计热身赛 B
  学到了DP的新姿势!显然按序列放是无法决策和转移的,我们不妨按颜色放。
  设\(f_{i,j}\)表示考虑了前i种颜色(一共贴着放了 \(\sum \limits_{k=1}^i c_k\)个方块),且有\(j\)处间隙左右两侧的颜色一样的方案数。
  转移的话,首先枚举第\(i+1\)颜色分成的段数\(k\)(每一段都贴着放若干个),再枚举其中有\(t\)段是放在之前颜色一样的间隙处的(\(t \leq min(j,k)\))。显然,放在别处位置的段数是\(k-t\)。我们用组合数取出\(j\)里面的\(t\)个和\(\sum \limits_{k=1}^i c_k\)\(+1-j\)里的\(t-k\)个,然后再做一个预处理\(G_{o,p,q}\)表示总共o个数,选出有顺序的p段和有顺序的\(q\)段(\(p\)\(q\)分别用于\(t\)\(k-t\))的方案数。这样就可以转移了。效率\(O(N^5)\)

12/15

J

Atcoder #86E
  这题感觉挺有意思呢。
  首先我们考虑DP。设\(f_{x,d}\)表示考虑\(x\)子树内的所有情况(显然一共有\(2^{size_x}\)种)中,与\(x\)距离为\(d\)那些点在经历了\(d\)步后在\(x\)正好还剩下一个的方案数。显然,初值\(f_{x,0}=2^{size_x-1}\)。计算\(f_{x,k}\)时,我们依次考虑它是那一棵子树里上来的。那么\(f_{x,d}=\sum \limits_{y \in Xson} f_{y,d-1}*{\prod \limits_{z \in Xson \&\& z \neq y} 2^{size_z}-f_{z,d-1}}\)。这个做一遍DP就好了。这样效率是\(O(N^2)\)的。
  看上去不能用数据结构维护,那么就考虑玄学复杂度分析了。注意到一个结论: 如果树上任意一个点\(x\)消耗的代价是它每一个子树的高度-它最高的子树高度,那么每一个点的代价和是\(O(N)\)的。这样,我们对每一个点的\(f_x\)开一个vector的结构,它继承它最大高度的儿子\(y\)的vector。每次暴力DP的时候,不能访问的位置就是\(y\)比别的子树高的部分。根据DP的过程,那些值只要都乘上一个2的幂次就好了。我就再对每一个点开了一个set \(G_x\),每次放入一个pair,表示\(f_x\)的某一段要全体乘一个常数。每次做\(x\)的时候,我们可以访问它的所有不是\(y\)的儿子,将它们的vector用G更新好再把\(y\)和别人重复的一段更新好,之后直接转移。\(y\)多出来的那一段再在G里加个pair即可。

12/19

CF #441 E
  显然要二分答案。首先,直接贪心判合法性是不对的,必须类似DP地扫过去。注意到每个阶段必然有一个点在\(x_i\)处,我们只需记录另一个点的位置。用一个容器存放另一个点可行的位置。考察\(x_i\)\(x_{i+1}\)的转移:如果是在\(x_i\)的点移动过去(那么容器里的点不动),只需要删除容器里一些不合法的位置(是一个前缀和一个后缀);反之,我们只需要看看容器里是否存在一个点能在合法距离下移动到\(x_{i+1}\),可以的话,就往容器里加入位置\(x_i\)。发现这些操作都可以用set维护。

12/23

wanna fly#6 F
  求n个点、最大匹配数为m的无标号无根树个数。这种东西不太熟练,搞了很久>_<
   首先无根树都是直接选取重心,当做有根树进行DP。不过必须保证每一个子树的size要\(\leq \lfloor \frac{n}{2} \rfloor\)
  然后就是求有根树的方案数。有一个最大匹配的要求,可以根据贪心的思路,设 \(f_{n,m,0/1}\)表示选了n个点,匹配数是m,且根是否还未匹配。
  主要的思路就是一点一点把子树背包进来。但是要处理以下一些问题:
  ①因为是无根树计数,儿子互相交换顺序算同一种方案,所以我们要强制size从小到大加入儿子。考虑到还有一个匹配数m,我们可以设一个二元组(p,q),随意规定一个小于号,就可以按顺序背包进去了。注意每次(p,q)可能会装入多个,用组合数转移一下;而且这样最好对(p,q)编号,方便预处理一个前缀和。
  ②如果采用比较自然的正向转移方法,是会出现问题的。比如现在的右儿子size还很小,如果我枚举的下一个右儿子的size很大,可能那种size的情况我还没有dp到过,无法获得转移的系数。所以我们必须每次在当前的总size下枚举右儿子的size',然后从\(f_{size-1-size'}\)处转移过来。但是如果这样操作的话,根处匹配数是否要+1(即\(f_{size-1-size'}\)处匹配数是否要减1)这种讨论,会比正向转移时麻烦很多。
  我采用的方法是套一个容斥。\(f_{n,m,1}\)肯定全是由\(f_{x,y,0}\)转移过来的;\(f_{n,m,0}\)要求至少有一个1的儿子,所以可以用\(f_{x,y,0/1}\)随意背包的答案减去只用\(f_{x,y,0}\)背包的答案。这样一来,就不需要讨论转移时匹配数+1/-1的细节了。
  最后, 注意n是偶数的时候可能会有两个重心,要把那些左边n/2个点,右边n/2个点,且树的形态不一样的那些方案减掉。

wanna fly#6 D
  有点考智商的题目……
  直接给出一个做法。我们称一个子集S是“极大不合法组”,当且仅当子集S的\(a_i\)之和小于m,而且不存在子集外的元素\(j\),使得\(a_i\)之和\(+a_j\)小于m。那么答案就是全集中的“极大不合法组”的个数。
  口胡证明:
  ①合法性:对于每一个“极大不合法组”S,我给不在集合里的点都分配一个新的钥匙。在全集中,任何一个不合法组T的并集必然小于k,因为它属于至少一个极大不合法组S,而S至少缺少一把钥匙;任何一个合法组T的并集必然=k,因为所有不合法组的补集与T的交至少为1。
  ②最优性:如果对于一个“极大不合法组”S我们不给他分配新的钥匙,设\(T=S \cup \{j\} j \not\in S\),那么T和S彼此的并集没有差别。

12.31/1.1

BUAA Summer Practice 2017 #2 数据结构专场 A
  可以等价于,给出一个01矩阵,求1的数量至少一半的面积最大的子矩阵。如果枚举上下两个边界,再把0变成-1,转化成一个新的模型:在N个数中选择一组\((i,j) (i<j)\),使得\(a_i<=a_j\),且\(j-i\)尽量大。
  看上去很经典,但是复杂度要求我们只能线性求解。事实上,因为是最远的,枚举j并维护单调栈时,必须要二分才能求出对于它来说最远的i。感觉有个不可突破的\(log\)。但其实在本题中,我们无需对每一个j求出,只要求全局最远的合法点对就好了。先考虑:如果\(j0<j1\)\(a_{j0}<a_{j1}\),那么\(j0\)必然不可能成为答案。这样可以搞出一个单调的\(j\)集合;同理也可以搞出一个单调的\(i\)集合。然后我们就可以在这两个数列上two point了。

CF GoodBye系列

51nod#32 C
  这题还是挺有意思的:区间每一个位置插入一个数,问区间所有数里的严格第K小值。数据范围看上去3个log都能过。
  我首先想到整体二分,花费了一个log的时间,将问题转化成了:每次区间加入一种颜色,或是询问区间里一共有多少种颜色。考虑直接动态维护这个问题(如果无脑套一个cdq的话,转化的问题好像不能在一个log内解决)。对于每一种颜色,我们开一个set暴力维护它目前覆盖的一些区间(注意实时保证这些区间不能有交,也不能接在一起);加入一个新区间的话,用一套set的骚操作,提取出新产生的一些完全没有被覆盖过的区间\(seg_1,seg_2,\dots,seg_k\),同时更新set里的区间。
  现在,对于每种颜色c,我们会得到一个新区间\(seg_i=[l,r]\),对于之后“还没有颜色c其它区间影响过”的询问答案要+1。再开一个set表示颜色c之前做过了哪些区间。假设\([l,r]\)左边那个是\([l1,r1]\),右边是\([l2,r2]\),那么符合要求的询问\([ql,qr]\)满足\(ql>r1,qr<l2\),且\([ql,qr]\)\([l,r]\)有交。“有交”可以再拆成三个子问题容斥一下。发现这就是一个在线的矩阵加,单点询问,直接log^2或者根号都可以做。(嘿嘿嘿,比赛时这一步我直接暴力循环使过了)。
  感觉题解的做法不知道高到哪里去了……首先我们直接用线段树维护区间。对于数值(颜色),直接开一个bitset维护。每次询问时,直接一段一段颜色扫过去即可。

51nod#32 D
  经常出现的模型。不过放在回文串里莫名感觉有点新鲜。直接用\(min\{len_x,len_y\}\)的套路去搞好了,每次把短的串插到长串的回文树里问一问即可。

51nod#32 E
  这题十分有趣呢。其实就是暴力维护这个阶乘的结构。
  开始想麻烦了,用可持久化线段树搞来搞去取预处理要分解的数“每一个质因子分别有几个”。其实只要枚举质因子搞过去就行了,\(kp+1~k*(p+1)\)这段阶乘的贡献是等价的;这样就能在\(O(N \log N)\)时间里处理好了。后来倒着枚举阶乘的时候我想错了,以为是只能用暴力,就对于每一个p维护了一个单调的结构,表示它剩下x个的时候最多能表示到y的阶乘。然后分别完某个阶乘k后,我取一个各个质因子中限制最小的y,直接跳过去并暴力分解。
  其实差点就想到正解了。枚举k可以直接暴力枚举下去,然后我们用一个小根堆维护每一个质数能贡献几个k!(分数类)主要是,k变成k-1时,小根堆里只有log个元素要改,别的元素减去的都是常数(总体打标记即可)。这样效率就是\(O(N \log N)\)了。

1.6

Atcoder Regular #087
  这题好有趣呀。
  先算算最大值是什么。我们考虑每一条边的贡献,显然,答案不会超过\(\sum min\{size_x,n-size_x\}\)。然后可以用调整法证明,这组解必然能取到。比如,考虑边\((x,y)\),不妨设\(size_x<size_y\):如果有一组匹配在子树x内部,那么必然至少有一组匹配在y子树内部;我们交换它们,结果肯定更优。
  以上证明也会帮助我们求方案数。我们要求合法排列的方案数,使得每一条边较小那一侧的点,全都跳向另一侧。不妨先找到一个重心R(子树必然小于等于另一侧),这样就简化成\(\forall x\),x子树里的点不能连向x。同时我们发现,这些限制是互相包含的。我们只需把R的直接儿子找到,分别满足它们的要求即可。
  最终的模型是:你有\(m\)组数,分别是\(a_1,a_2,\dots,a_m\),且总和是\(n\)。要给每一个数定一个不重复的目标(即求一个排列),且一个数不能指向它自己组的数。DP很难做,考虑直接容斥。我们先DP出“n个数里组合地选出\(k\)个,强制它们都连向自己组”的方案数,设为\(f_k\)。那么答案就是\(\sum {-1}^k*f_k*(n-k)!\)。效率\(O(N^2)\)

1.8

51nod 1792
  比较有趣的细节题。
  对于每一个总的询问\((ql,qr)\),一个暴力的做法是:
  我们枚举一个线段树里的节点\((l,r)\),单独考虑它的所有贡献。对于\(ql \leq x \leq y \leq qr\)的这么多组\((x,y)\)线段中,我们先求出与\((l,r)\)有交的线段数,再减去完全覆盖\((l,r)\)父亲的线段数,即求出了贡献。
  可惜这样复杂度太高了。考虑线段树的复杂度。当我们做到一个\((l,r)\)满足\(ql \leq l,r \leq qr\)时,要\(O(1)\)出解,不能再递归下去了。注意到对于\((l,r)\)子树里的一个区间\((l',r')\),以上两个计算的部分都可以写成有关于\(ql,qr,ql*qr,ql^2,qr^2,1\)的线性组合。我们只需在最开始预处理这些系数,再对系数求个子树和,即可支持\(O(1)\)询问。

posted @ 2018-02-09 09:53  了491  阅读(531)  评论(0编辑  收藏  举报