• 一些比赛的题解(共32场)


    之前写在本地的,丢上来测试一下

    1. Educational Codeforces Round 56

    E

    题意:映射后即为,给一个排列,支持两种操作:询问区间[lb,rb]内权值在[la,ra]内的数字个数,交换两点的值。

    key:树套树

    树状数组套主席树,空间吃紧。注意到历史版本没有被别的继承并且不再访问,所以可以回收这些点的空间。

    F

    题意:给一个序列,每个点可以放权值在[1,k]中的数,序列上有些已经填好了。问没有连续len个数相同的方案数。

    (lenle nle 10^5,kle 100)

    key:dp,滑窗

    对于每种权值k维护一个滑窗,分别是以i结尾长度为连续的0,1...len-1个k的方案数。每次转移时:

    若当前是-1,则可以放一个k(长度为0...len-1变成1...len),或者放一个别的(长度为0),后者是所有滑窗的总和减去当前滑窗。

    否则,若是x,则对于x则长度为0...len-1的变成1...len,长度为0的方案数是0。对于非x的滑窗只剩下长度为0的,方案数是x的滑窗之和。

    于是只需要维护所有滑窗的和和每个滑窗的和即可。注意弹出尾部。复杂度(O(nk))

    2. Educational Codeforces Round 54

    B

    题意:n每次减去它的最小质因子,问操作几次变成0.

    key:数学

    偶数则一直-2,奇数则减去它的最小质因子(必定为奇数),之后一直-2.

    E

    题意:给一棵树,每次操作把ui节点子树内距离ui<=di的点+xi,问最终每个点点权。

    key:dfs,离线,树状数组

    转化成深度在区间内的点+一个数,dfs+树状数组,回溯时删去对应区间。

    F

    题意:一个序列被分为n份,每份内有ai个A类物品和bi个B类物品,排成一排。问是否存在一种安排方案使得没有连续k+1个相同的物品。

    key:贪心,讨论

    显然的贪心,转化为上一份最后是resa个A类物品或者上一份最后是resb个B类物品,再安排当前份中的物品,要使得转以后的resa和resb最小。分别考虑后取优。

    假设X和Y类物品,上一份最后剩余dx个X类物品。需要考虑这几类情况:

    1. 无解。即X非常多或者Y非常多。假设X非常多,则此时是每连续放k个X然后再放一个Y,此时仍然会有非法情况。
    2. 不可能剩下X或者Y。假设不可能剩下Y,则此时是每连续放k个X然后再放一个Y最后Y用完时X剩余的个数<=k。
    3. X或者Y剩下1个。即一般情况,二者的数量差距并不大。

    分别考虑后就能AC。

    G

    题意:二人博弈,游戏为:现有序列 (b_1,b_2...b_k) ,在长度为k的序列上,初始在1并且(b_1-1),之后若在x,则玩家的目标点为(yin[x,min(k,x+m)]),要求目标点的(b_y>0),并且移动后(b_y-1)

    给一个长度为n的序列,支持两个操作:区间+di或者询问若以某一区间博弈的赢家。(n,qle 2*10^5,mle 5​)

    key:博弈,线段树

    由于可以原地踏步,并且移动到该点则该点的权值-1(奇偶性反转)。根据有向图游戏,当前点若本来是偶数则必胜;否则若之后m个有必败态则必胜,没有则必败。

    于是可以进行转移。考虑线段树维护:加一个偶数相当于没加,奇数相当于反转。每个区间维护:对于当前区间右端点之后m个态的2^m种取值,每种得到的结果是多少(也要存最开始的m个态来转移)。然后就可以区间合并了。维护反转操作,只需要初始化时记录一下即可。(O(n*2^mlogn))

    3. CodeCraft-19 and Codeforces Round #537 (Div. 2)

    D

    题意:给一个字符串,由至多52种字符组成,每次询问两个字符x和y,问有多少种重排方案使得所有同类字符在前一半或者后一半,并且x和y必须在同一半。(n le 10^5​) 且为偶数

    key:组合数学,01背包

    首先统计每种字符的出现次数,记为(t_i)。先不考虑x和y,对于一种合法方案,需要选出一个子集使得其和为n/2,它的排列方案是((n/2)!/prod t_{k_i}!),剩下的形式相同,所以对于一种选取方法,对应的方案数是

    [W=frac{(n/2)!*(n/2)!}{prod_{i=1}^{52}t_i!} ]

    所以最终答案为2*W*d,其中d是选取一个无序集合使得其和为n/2的方案数。

    对于该问题,即最终答案为2*W*d,其中d是选取一个无序集合使得其和为n/2且x和y必须被选的方案数。

    对于计算d,这其实是一个01背包计数问题,可以处理出方案数,之后再退掉两个物品即可。复杂度(O(52^2*n)​),因为常数小故可以通过。

    Claris提出一种优化:由于我们只关注f[n/2]的答案,所以退掉第一个物品 i 是52*n,退第二个物品 j 时,对(t_j)相同的一起处理。改变f[n/2]的元素只有至多(f[(n/2)/t_j])个,所以复杂度是(O(52 imes (n/2/1+n/2/2+...+n/2/52))=O(26nlogn))

    E

    题意:给一棵树,每次询问指定树根(r_i),给一个点集({a_i}),要将其划分成至多(m_i)组,使得每组不存在两个点是祖先和孙子的关系,问方案数。(nle 10^5,m_ile 300,sum|a_i|le10^5)

    key:dp,dfs序,lca

    考虑一组询问:把点集按dfs序排序,(f[i][j])为前i个点划分成j个集合的方案数,则

    f[i][j]=f[i-1][j-1]+f[i-1][j]*(j-h[node[i]])

    其中h[x]为给定点集中x的祖先个数。

    可以发现这个dp顺序只要满足x在x的所有祖先计算之后再计算就可以了(因为只需要考虑x和x的祖先的约束),所以可以按照bfs序排序,即x与根的距离,也就是h数组。

    对于多组询问,我们只要计算出h数组,然后对点集排序,然后dp就可以了。而计算h相当于计算点到根的路径上有多少个被标记点,这个可以用dfs序实现。由于动态,所以需要树状数组。

    复杂度为(O(300n+nlogn))

    4. Codeforces Round #536 (Div. 2)

    AK了,三发罚时有点可惜:数组开小+1,思路错+1,没考虑特殊情况+1

    E:dp

    F:离散对数(BSGS,原根)+矩阵乘法+exgcd

    5. Codeforces Global Round 1

    D

    题意:给n个物品,每个物品有一个权值,每次可以拿走形如[x,x+1,x+2]或者[x,x,x]的三元组,求至多拿走多少个。(a_i,nle10^6​)

    key:dp

    可以注意到若拿三个[x,x+1,x+2]可以将其分为拿三个[x,x,x],所以可以认为对于每一个x,[x,x+1,x+2]至多拿两次。

    考虑dp:(f_{i,j,k})表示拿到权值为i的物品,拿了j个[i-1,i,i+1],k个[i,i+1,i+2]的最大个数,枚举[i+1,i+2,i+3]拿多少个转移即可。

    注意不能对当前和上一个物品的个数dp,这样可能会漏掉一些状态。

    E

    题意:给序列a和序列b,每次可以把(a_i)变成(a_{i-1}+a_{i+1}-a_i),问能否把a变成b。

    key:差分序列

    这个之前在知乎上看到过……每次变换相当于交换差分序列相邻两项,所以只需要判断a和b的差分序列是否相同,还需要判断a和b序列的第一项是否相同。

    F

    题意:一棵树上点的标号是由 dfs 序顺次标,每条边有权值,q 次询问点 (v_i​) 到标号在 ([l_i,r_i]​) 的叶子的最短距离是多少。 (n,qle5*10^5​)

    key:dfs序,dfs,线段树

    标号的性质:一棵子树的节点是连续的。或者可以认为点标号 = dfs 序标号。

    考虑离线:每次处理 (v_i) 相同的所有询问。

    首先处理出来所有叶子到 1 的距离。然后对树做 dfs ,每次从 u 到 v 时,设边权是 w,查询点到 v 子树内的叶子的距离减少 w,到 v 子树外的叶子的距离增加 w。于是用线段树维护区间加和区间最小值即可。

    G

    题意:给一颗树,树上有些点已经涂了 W。W 和 B 二人轮流涂色,W 先,率先涂出相邻三个 W 或者 B 的人赢,问谁赢或者平局。 (nle 10^5​)

    key:讨论

    显然 B 不可能赢,所以就看 W 是否能赢。相当于在树上下三子棋,B 的最优策略就是在 W 下完之后立马占领它的相邻点,否则必输。

    大概分几种情况讨论讨论就行了,下面是 W 赢的情况(n>3,小于的情况特判):

    1. 已经存在连续两个 W。
    2. 两个 W 中间空一格。
    3. 存在大于等于四度的点。
    4. 三度点,且其中至少两个相邻点不是叶子。
    5. 已经被涂上 W 且不是叶子。
    6. 已经被涂上 W 且是叶子,且相邻点的度数大于等于 3。

    排除以上情况,树的形态只能是一条链然后端点是三度点,所以还剩下三种情况:一条链,一条链且其中一个端点是三度点,一条链且两个端点都是三度点。对于染色情况,只会在非三度点的端点染色。

    1. 一条链:当且仅当两个端点都是 W ,且 n 是奇数。

    2. 一条链且其中一个端点是三度点:非三度点的端点是 W,且 n 是大于等于 6 的偶数。

    3. 一条链且两个端点都是三度点:n 是大于等于 7 的奇数。

    前六种手玩即可。容易知道对于后三种,最终胜利的子局面一定是情况 2 或者情况 6 ,观察即可得。

    H

    题意:定义一个数字串是 modest 当且仅当其在 [l,r] 之间且没有前导 0。构造一个长度为 n 的数字串,使得其 modest 的子串数目最多,多种答案求字典序最小。 (lle r le 10^{800} , n le 2000​)

    key:AC 自动机,dp

    以下用正则表达式来表达一个字符串。[x-y] 表示匹配一个在 x 到 y 范围内的字符,{k} 表示重复匹配 k 次。

    首先严格定义一个 modest 串。当 (|l| e |r|) 时, 一个串 S 是 modest 串当且仅当其被以下三个正则表达式之一匹配:

    1. (l_0 l_1 l_2 dots l_{x - 1} q [0-9]{|l| - x - 1}​) ,其中 (q > l_x​)
    2. (r_0 r_1 r_2 dots r_{x - 1} q [0-9]{|r| - x - 1}​) ,其中 (q < r_x​)
    3. ([1-9][0-9]{x - 1}​) ,其中 (|l| < x < |r|​)

    按长度分类易知一个串至多只被其中一个正则表达式匹配。当 (|l|=|r|) 时和上述相似。

    我们称 ([0-9]{k}) 是一个长度为 k 的通配符。于是将以上三个正则表达式去掉所有的通配符剩下的前缀拿出来,建立 AC 自动机(一共有 (O((|l| + |r|) cdot Sigma) + 9) 个字符串),然后将每个字符串对应的通配符存到对应的节点上。该问题就变成一个 AC 自动机上的 DP。

    ((i,v)) 经过数字 (d) 转移到 ((i+1,u)) 时,需要将 (u) 对应的字符串的贡献加上。易知贡献为以 u 结尾的所有字符串的所有通配符中,长度小于等于 (n-i-1) 的个数。换句话说,就是 u 所对应的 fail 树的祖先节点中通配符长度小于等于 (n-i-1) 的个数。这个东西可以预处理。总复杂度为 (O((|l| + |r|) cdot n cdot Sigma ^ 2)) ,其中 (Sigma) 是字符集大小,即是 (10)

    补充一句,为了方便输出答案,可以添加一个 “0” 的字符串,用来处理答案有前导0的情况。

    6. Codeforces Round #538 (Div. 2)

    AK了,都不算难。

    F:支持区间乘x,询问区间积的欧拉函数值,权值<=300。

    300以内的素数有62个,压位后变成询问区间积和区间或,线段树即可。

    7. Educational Codeforces Round 59

    C

    主要是看错题了,虽然耽误了一个小时,但是感觉看错后的题比较有意思。下面说看错了的题意。

    题意:给一个字符串,每个点有一个权值 (a_i) 。选择多段区间,每段区间中任意字符出现次数要<=k,区间权值是每个元素的权值和。问所有区间权值和最大是多少。

    key:dp,线段树

    对于点 i ,若选择了它,则可以根据 k 和字符串处理出最小的 (pr_ile i​) 使得 (str(pr_i,i)​) 不合法。

    (f_{i,0/1}​) 表示前 i 个,第 i 个不选/选的权值和的最大值。则有如下式子:

    [f_{i,1}=f_{j,0}+S_i-S_j , j in [pr_i-1,i-1] \ f_{i,0}=max{f_{j,1}} , j<i ]

    然后就是一个线段树维护的 dp。

    D

    题意:给一个 n*n 的 01 矩阵 A,定义将矩阵 A 进行 (x)-压缩 为矩阵 B 当且仅当 x 是 n 的因数且对于任意的 i 和 j, (A[i][j] = B[lceil frac{i}{x} ceil][lceil frac{j}{x} ceil]) 成立。问 x 最大是多少。

    key:暴力,复杂度

    其实做法很简单,只是复杂度当时算错了…

    题意换句话说就是,将 A 切分成等大的若干个正方形,使得每一个正方形内元素相同,问正方形边长最大是多少。

    第一种做法:预处理前缀和,于是可以 (O((frac{n}{x})^2)) 进行check,总复杂度 (O(sum_{x|n} frac{n^2}{x^2}) = O(n^2*sum_{x|n} frac{1}{x^2}) = O(n^2)) 。因为 (sum_{n=1}^{infty} frac{1}{n^2}=frac{pi^2}{6})

    第二种做法:可以发现当 x*p 合法时,x 也合法。于是可以对 n 分解质因数,然后枚举幂来check。此时若不用前缀和,复杂度是 (O(n^2logn)) ,但这个 log 特别小所以也没什么问题。如果用前缀和,那么复杂度和上面一样。

    E

    题意:给一个 01 串,每次可以选择相同且连续的一段,记长度为 (i) ,将其消去,并将剩下的两个串连接,此时得分为 (a_i) 。问若干次消除后的最大得分。 (nle100)

    key:区间dp

    区间 dp。因为有可能连出来多个连续相同字符而不把整个区间同时消除,所以状态要比普通的区间 dp 多记录一些信息。

    (f_{c,l,r,k}​) 为将区间 ([l,r]​) 消到剩余 k 个字符 c 的最大得分。于是有如下式子:

    [f_{c,l,r,k}=max{f_{c,l,i-1,0}+f_{c,i+1,r,k-1}} , s[i]=c, lle ile r, kge 1 \ f_{c,l,r,0}=max{max{f_{0,l,r,k}+f_{1,l,r,k}}+a_k} ]

    第一个式子是枚举剩余的 k 个字符 c 的第一个出现位置在哪里,此时需要把左边全部消掉,右边剩余 k-1 个字符 c。

    复杂度 (O(n^4)) 。实现时要注意非法状态和枚举顺序(写记搜比较好)。

    F

    题意:n 份贷款,第 i 份在买入时将有 (a_i) 的收益,此后每个月都将损失 (b_i) ,直到 (k_i) 个月之后停止。每个月至多只能买入一份贷款,每份贷款至多只能买一次,问合理安排后在某一天的最大收益是多少。 (n le 500)

    key:二分图最大权匹配(KM算法)

    必然只在1~n天买入。假设第 i 份贷款在第 j 天买入,则在第 e 天的收益是 (a_i-min(e-j,k_i)*b_i) 。于是假设在第 n 天收益最大,则可以得到第 i 份贷款在第 j 天买入的收益。于是变成二分图最大权匹配问题。

    二分图最大权匹配,用 KM 算法是 (O(n^3)) 可以通过。用网络流是 (O(k*spfa)) ,这里是一个完全二分图,所以跑的巨慢无比…

    G

    题意:给数列 (c_i​) 和递增数列 (d_i​),定义一个区间 ([l,r]​) 的权值是 (sum_{lle ile r}a-c_i + max_{lle ile r-1}(d_{i+1}-d_i)^2​) ,问区间权值最大是多少。 (n le 3*10^5​)

    key:单调栈,线段树

    算法1

    枚举左端点 l,考虑每一个 r 的答案。l 每减少 1,对于每一个 (r in [l,n]) 都增加了 (a-c_l) 。此时需要尝试用 ((d_{l+1}-d_l)^2) 去更新每一个 (rin[l+1,n]) ,相当于与原先的值比较大小,若新值比它更大,则替换掉并更新答案。

    前者可以用线段树区间加和 RMQ 直接维护,后者不可以直接维护(因为新值替换掉的旧值的答案不一定是最优解)。因为每一个 ((d_{l+1}-d_l)^2) 所管辖的区间是一定的,于是新值替换掉的旧值也是一定的。用单调队列维护 ((d_{l+1}-d_l)^2) ,每次新值覆盖旧值时直接把旧值从对应区间减去,最后再把新值加入。由于每一个 ((d_{l+1}-d_l)^2) 至多插入一次、删除一次,所以总复杂度是 (O(nlogn))

    算法2

    这里是题解的做法,对 ((d_{l+1}-d_l)^2) 排序,记为 (a_i) 。枚举 (a_i) ,每次处理它的贡献,即处理跨过它的区间。可以用 set 找到左右区间,用 RMQ 来处理询问。 (O(nlogn))

    算法3

    本质即为区间和+最大相邻差值的平方,而第二个可以直接单调栈,而区间和可以用前缀和做,所以可以用单调栈实现一个线性做法。

    在做单调栈的同时枚举右端点,并记录相邻差值的平方取 (a_i)(sum_l) 的最小值,于是就可以直接更新。

    8. Codeforces Round #533 (Div. 2)

    E

    题意:m 个点,指定 n 个点集使其两两连边,求最大独立集。 (m le 40)

    key:状压搜索,复杂度

    这个题主要是看错题意…

    显然可以做一个 meet in the middle。这里说一个题解给的很奇妙的做法,复杂度是 (O(2^{m/2}))

    定义 (solve(S)) 为点集为 (S) 时的最大独立集,则每次枚举 (p in S)

    1. 不选择 p ,则答案为 (solve(S xor 1 << p))
    2. 选择 p ,则 p 的邻居都不能被选,则答案为 (solve(S and G_p)) ,其中 (G_p) 是与 p 不相邻的点集。

    关于复杂度为什么是对的,题解是这样解释的:

    Consider the recursion, there are at most (m/2​) recursion calls before we arrive into the state, where there are no set bits of the first half.

    我理解的是,两种情况都会把 p 删去,第二种情况删的更多,最坏时第二种情况每次只删掉 1 个,于是每次删去 1 个或者 2 个元素,复杂度就是 (O(2^{m/2})​) 了。

    *9. Codeforces Round #534 (Div. 1)

    C

    题意:给一个每个点度数 (ge 3) 的无向连通图,给定 (k),求要么找出一条长至少为 (frac{n}{k}) 的链,要么找出恰好 (k) 个环使得每个环的长度大于 (3) 且不是 (3) 的倍数且每个环上都存在一个点在其它输出的环上没出现过,要么输出 (-1)(kle nle2.5*10^5 , mle5*10^5)

    key:构造,定理

    先以 (1) 为根建一棵 dfs 树。

    定理:深度 (lefrac{n}{k}) 的树至少有 (k) 个叶子。

    证明:设有 (c) 个叶子,设第 (i) 个叶子到根经过的点数是 (x_i) ,则有 (sum x_i ge n) ,抽屉原理有 (max{x_i}=deep ge frac{n}{c})

    于是若深度 (ge frac n k) ,则找到一条合法的链。

    否则,考虑每个叶子 v:由于度数至少是 3,所以至少存在两条返祖边,设其连向 (x)(y) ,此时得到三个环,长度分别是 (d(v,x)+1 , d(v,y)+1 , d(x,y)+2) 。其中必定存在一个的长度不是 3 的倍数,于是得到一个环,而点 v 只会出现在这个环上。

    不存在无解情况。

    D

    题意:给 n 个数 (a_i​) ,对于每个数可以除掉它的一个不超过 k 的因子,花费为 (c_i​) ,目标是让 (a_i​) 的 gcd 为 1。若对下标集合为 (I​) 的所有数做了操作且达成目标,求 (|I|*sum_{iin I}c_i​) 最小。 (nle10^6 , a_i,kle10^{12}​)

    key:素数,dp,剪枝

    先求出所有 (a_i​) 的 gcd,再分解质因数,得到的素数个数一定 (m le 11​)。之后只需要关注这些素数即可。若对一个数进行操作,一定是直接消除某些素数,所以至多选 (m​) 个数。所以只要根据 (k​) 处理出每个数可以消除的素数集合,就得到一个 (O(ncdot m cdot 3^m)​) 的 dp ,显然过不了的。接下来就是这个题的神奇之处:

    剪枝 1

    将不是目标素数的素数全除掉得到一组新的 (a_i),然后把相同 (a_i) 压缩起来,对应的所有 (c_i) 只保留最便宜的 (m) 个,那么至多只剩下 (O(M*m)) 个物品(而不同的 (a_i) 只有 (M) 个),其中 (M < 12000)

    (M) 取最大时,一定是取最小的 (m) 个素数,因为 (a_ile10^{12}) ,可以通过程序暴力得到:

     1    39
     2   469
     3  2369
     4  6734
     5 10808
     6 11598
     7  7815
     8  3462
     9   895
    10   110
    11     4
    

    左边是 (m) ,右边是对应上界 (M) 。现在复杂度变成 (O(Mcdot m cdot 3^m)) ,仍然不能接受。

    剪枝 2

    因为最终至多只选 m 个,大部分被选中的机会很少甚至根本不会被选,这由它们每个管辖的素数集合和花费有关。可以预处理 (ok[S]) 表示素数集合为 (S) 时那些数可能被选,而对于每个 (S) ,至多存储 (m) 个最便宜的数即可。然后按数字顺序做 dp。

    这样所有的转移方向至多只有 (m*2^m) ,再枚举当前选了几个数,总的转移复杂度是 (O(m^2*3^m))

    于是步骤是:

    1. 对 gcd 分解质因数。
    2. 压缩 (a_i) ,用每个(a_i)(c_i) 预处理 (ok[S]) ,此处复杂度是 (O(Mcdot2^mcdot m))
    3. dp。 (f_{i,S}) 表示选了 (i) 个数,当前消除的素数集合是 (S) 的花费最小是多少,转移复杂度 (O(m^2cdot 3^m))

    E(待补)

    题意:给出 (n) 个数,从中连续选出 (n) 个数(可重复选)计算它们的 radix sum,求对所有的 (i in [0,n)) radix sum 为 (i) 的方案数。

    radix sum 定义:设 a 和 b 的 radix sum 为 (s(a,b)​) ,则 (s(a,b)=(a_1+b_1)mod 10, ldots ,(a_k+b_k)mod 10​) ,其中 (a,b​) 的数位分别是 (a_1...a_k,b_1...b_k​) 。即十进制下的不进位加法。多个数的 radix sum 定义:(s(t_1, ldots ,t_n)=s(t_1,s(t_2, ldots ,t_n))​)(n,x_i< 10^5​)

    key:多项式

    10. Educational Codeforces Round 60

    C

    题意:二维平面上指定起点和终点,再给出周期为 n 的风向变化,每单位时间可以选择一个方向移动一单位长度或者停止不动,并且随风走 1 单位长度(方向是上下左右)。问到终点的最短时间。 $n le 10^5 , sx,ex,sy,ey le 10^9 $

    key:二分

    主要是想了很久却没想到二分……

    t 时间内能到的充要条件是:起点经过 t 时间内风的偏移量后距终点的曼哈顿距离 (le t) 。因为每单位时间都可以向终点逼近一步。所以二分一下答案就行了……

    E

    题意:这是一个交互题。对一个字符串按顺序进行若干次操作,每次操作形如:把位置在 (a_i)(b_i) 的字符交换。现在给定操作后的字符串 (s) ,你至多可以询问三次,每次给出一个字符串然后返回该字符串操作后得到的字符串,输出 (s) 操作前的字符串。 (|s| le 1000)

    key:交互,思维

    即想知道:第 (i) 个位置的字符操作前在哪个位置,记为 (d_i)

    可以考虑如此细分:若第 (i) 个位置操作后是字符 (c) ,则 (d_i in c) 出现过的所有位置。下一次再将 (c) 出现过的所有位置细分成 26 个字符,则 (d_i) 的取值范围变成原来的 (frac 1 {26})。由于 (1cdot26cdot26<10000,1cdot26cdot26cdot26>10000) ,所以只需要三次即可。

    举例来说,设字符集为 3,三个字符串可以取:

    aaaaaaaaabbbbbbbbbccccccccc
    aaabbbcccaaabbbcccaaabbbccc
    abcabcabcabcabcabcabcabcabc
    

    F

    题意:给一个字符串,设字符集为 (p) ,再给出 (pcdot p) 的对称二元矩阵 (A)。定义一个字符串是 crisp 当且仅当对于任意两个相邻字符 (i,j)(A[i][j]=1) 。对于初始字符串,每次操作可以删除某个字符所有出现位置并将剩余部分拼接起来,要求每次操作后得到的字符串都是 crisp 的。问若干次操作后得到的字符串长度最短是多少。 (p le 17, n le 10^5)

    key:高维前缀和

    只要预处理出来两个不可相邻字符 a,b 中间有哪些字符出现了,那么如果 a 和 b 没有被删掉,但中间出现的字符都删了,那么就不合法。统计这个只需要扫一遍即可。

    之后就需要一个高维前缀和,将所有满足 a 和 b 没被删,中间出现的都被删了,其他随意的状态全部标记,之后跑一个 dp 即可。

    高维前缀和:

    for(int k = 0;k < m;k ++)
        for(int l = 0;l < (1<<m);l ++)
            if(l >> k & 1)
                tmp[l] |= tmp[l^(1<<k)];
    

    即一维一维地算前缀和。

    G

    题意:给一个长度为 n 的排列,定义一段区间的权值为:这段区间形成的笛卡尔树,每个点的子树大小的和。q 次询问一个区间的权值。 (n,qle 10^6)

    key:线段树

    先只考虑左子树大小的和,右子树对称。

    其实就是统计有多少 $a_i>a_j,j<i , 满足 a_k<a_i ext{ for (i<k<j)}$ 的点对个数。

    所以可以处理出来每个点影响的区间,然后离线按左端点排序。先把所有区间插入(即区间+1),扫的时候删除,答案即为对应的区间和。

    *11. Codeforces Round #539 (Div. 1)

    C(待补)

    题意:你有个数字 (v​) 和每秒增量 delta,即平均每时刻过去都要将 (v​) 加上 delta(此处时间是连续的)。q 次操作,每次为:在 (t_i​) 时刻将 delta 修改为 (s_i​) 、删除在 (t_i​) 时刻的事件、询问在 ([l_i,r_i]​) 时刻初始值为 (v_i​) 时第一次变为 0 的时间点。 (q le 10^5​)

    D

    题意:n 个点的带标号树,边权取值是 [1,m] ,问有多少个不同的树满足标号 a 和标号 b 两点的距离恰好等于 m。 (n,mle10^6)

    key:计数,定理

    Cayley's formula 的一般化:(n​) 个带标号点形成 (k​) 棵树的方案数为 (T_{n,k}=k*n^{n-k-1}​)

    枚举 a 和 b 之间的距离 k ,则其中有 k-1 个点。隔板法可得这条链上点和边的方案数是 (inom{m-1}{k-1}cdotinom{n-2}{k-1}cdot(k-1)!)

    剩余的边权值随意,点的分配可以看做所有的 n 个点形成 k+1 个森林,然后把链上的 k+1 个点选出来连上。所以总方案数是:

    [inom{m-1}{k-1}cdotinom{n-2}{k-1}cdot(k-1)!cdot m^{n-k-1} cdot T_{n,k+1} ]

    E

    题意:给 n 个数,支持区间乘、单点除(保证整除)、求区间和,需要模 mod(不一定是素数)。 (n,q,x_ile10^5)

    key:线段树,数论

    唯一的问题在于单点除时可能没有逆元。考虑将 mod 唯一分解,而 (10^5) 内的数唯一分解后素数不超过 7 个,设素数向量为: (p_1dots p_m)

    需要在线段树的叶子节点维护:该点权值除去每个素数后剩余部分模 mod 的值、每个素数的幂次。单点除时直接更新。

    对于区间乘,除了对答案的修改需要打标记下传以外,还需要下传叶子所维护的信息。

    这样复杂度是 (O(7nlog^2n)) ,预处理快速幂后复杂度是 (O(7nlogn))

    F(待补)

    *12. 2018 China Collegiate Programming Contest Final

    CDEFHJ

    K

    题意:求 a 使得 (a^{2^{30}+3} equiv c mod n) 。其中 n 是相邻两素数乘积。 (n,c le 10^{18})

    key:数论

    两边同时 (1/(2^{30}+3)) 次方,得到 (a = c^{d} mod n) 。其中 d 是 (2^{30}+3) 在模 (phi(n)) 下的逆元。快速幂即可。

    13. 2018 Arab Collegiate Programming Contest

    单挑 9 题舒服啊,再给十几分钟就 10 题了,水题欢乐赛真开心(

    K

    题意:构造一个长度为 n 的数列,每个元素取值范围在 [L,R] 之内,且模 3 为 0 的子段和个数恰好为 k,问方案数。 (n,k le 10^4​)

    key:dp,数学推导

    取值范围无所谓,可以看做填 0/1/2 。

    若有解,则 k 一定是 (O(n^2)) 的一个东西。假设做出来的结果中,前缀和对 3 取余为 0,1,2 的个数分别是 (x,y,z) ,则必须满足

    [x+frac {x*(x-1)}{2} + frac {y*(y-1)}{2}+frac {z*(z-1)}{2}=k ]

    然后发现有解的 n 至多是 245 。

    然后就很简单了,直接用上面的变量之间作状态: (f[i][j][k][l]​) 表示长度为 i ,前缀和对 3 取余为 0,1 的个数分别是 i,j ,当前 i 个数总和对 3 取余是 l 的方案数。

    *14. 2017-2018 ACM-ICPC, Asia Tsukuba Regional Contest

    DEGHJK

    E(待code)

    题意:给一个长为 n 的序列 a,每个点为黑或白,每次操作可以将一个长度小于等于 k 的区间涂白或者涂黑,问变成序列 b 的最少操作次数。 (n le 5*10^5)

    key:dp,单调队列

    考虑 dp。 (f_i) 表示前 i 个格子一样的最少操作次数。考虑转移。可以枚举 j<=i ,把 [j,i] 全涂成 i 点的颜色,然后再将 [j,i] 区间内的点涂成一样的。后者发现是区间内黑白的段数。

    用单调队列扫一遍即可。

    G(待code)

    题意:在一个边长为 1 的四面体上, a 和 b 两点都在某一顶点 A,它们要沿某一面的某一方向移动长度 x,y,穿过棱后方向不变,问最终是否在同一个面上。

    key:讨论,六边形坐标系

    把四面体展开,复制到整个平面,发现是在一个夹角为 60°,每个单元格是正三角形的坐标系内,判断一下即可。

    *15. 2018-2019 ACM-ICPC Brazil Subregional Programming Contest

    AHIJM

    A

    题意:n*m的点阵,问两点连线不经过其他点且长度在 [L,R] 区间内的点对数。 (n,m,L,Rle 10^5)

    H(待code)

    题意:给一个字符串 S,给一个树,每个节点上有一个字符。需要支持单点修改、询问 u 到 v 路径上形成的字符串中 S 出现了多少次。 (|S| le 100, n,q le 10^5​)

    key:树剖,线段树,hash

    树剖转区间,维护 hash 值。 (O(n|S|log^2n))

    J

    题意:平面上给 n 个点,其中 k 个关键点,询问最小欧几里得距离生成树。其中每个关键点至多连接一个非关键点。 (nle100, kle min(n,9))

    K

    题意:给 n 个圆,每个圆都包含原点,没有三圆交于一点也没有相切。询问交点个数,若大于 2*n 则输出 greater。 (n le 1.5cdot 10^5)

    M

    题意:给一个 M 个语句、n个变量的或与表达式,每个语句至多包含三个变量。每个语句中要么一个变量为真要么三个变量为真,问合法的指派中字典序最大的是多少。 (M,n le 2000)

    *16. 2018-2019 ACM-ICPC, Asia Seoul Regional Contest

    HI

    E:二分,坑题,需要判x=0时必须分在第一份,不能划分到第二份。

    C

    题意:给 n 个圆,需要把它们放到一条线上,保证对于任意排列只存在相邻两个圆相切(即最大半径与最小半径的比值小于4)。问所有排列中总长度最小是多少。 (n le 1000)

    key:构造,打表找规律

    对于一个排列,总长是第一个的半径+最后一个的半径+2*相邻两个的半径乘积再开根号。

    打表(dls写了个随机+遍历所有排列+输出解……一眼就看出规律)可找出规律。

    按半径排序后,n 是偶数时唯一,n 是奇数时只有可能是两种情况。

    G

    题意:给定 (s,w_a,w_b) ,求积分

    [int_0^s m dx ( int_x^{min(x+w_a,s-w_b)}w_b m dy + int_{max(x,s-w_b)}^{min(x+w_a,s)}s-y m dy) ]

    key:数学

    讨论,展开。避免浮点数所以要*6。

    LL work(LL s,LL wa,LL wb,LL wc) {
        LL tmp = 6*(s - wa - wb) * wa * wb;
        tmp += 6*wa * (s - wb) * wb;
        tmp -= 6*wb * (pf(s-wb) - pf(s-wa-wb)) / 2;
    
        LL ans = 0;
        if(wa >= wb) {
            LL ans2 = 0;
            ans += 6*(pf(s-wa) - pf(s-wa-wb)) / 2;
            ans += 6*(wa + wb - s) * wb;
            ans += 6*wb * (wa - wb);
            ans += 6*s * wb;
            ans -= 6*(pf(s) - pf(s-wb)) / 2;
    
            ans2 -= 6*(lf(s) - lf(s-wb)) / 6;
            ans2 += 6*pf(s-wb) * wb / 2;
            ans2 -= 6*(pf(s)-pf(s-wb)) * (wa-wb) / 2;
            ans2 -= 6*pf(s) * wb / 2;
            ans2 += 6*(lf(s) - lf(s-wb)) / 6;
    
            ans *= s;
            ans += ans2;
        }
        else {
            LL ans2 = 0;
            ans += 6*(pf(s-wb+wa) - pf(s-wb)) / 2;
            ans += 6*(wb - s) * wa;
            ans += 6*(wb - wa) * wa;
            ans += 6*s * wa;
            ans -= 6*(pf(s) - pf(s-wa)) / 2;
    
            ans2 -= 6*(lf(s-wb+wa) - lf(s-wb)) / 6;
            ans2 += 6*pf(s-wb) * wa / 2;
            ans2 -= 6*(pf(s-wa) - pf(s-wb)) * wa / 2;
            ans2 -= 6*(wb - wa) * pf(wa) / 2;
            ans2 -= 6*wa * pf(s) / 2;
            ans2 += 6*(lf(s) - lf(s-wa)) / 6;
    
            ans *= s;
            ans += ans2;
        }
        return tmp + ans;
    }
    

    J

    题意:无向图,有些点属于 A 类,剩余是 B 类。再标记某些点是 C 类,问是否存在 A 类的点 a 到 C 类 的点 c1,B 类的点 b 到 C 类 的点 c2,所形成的路径上的边权形成的序列相同。 (n le 1000,边权 le 20)

    key:搜索

    (f[i][j]) 表示某个 A 类点走到 i,某个 B 类点走到 j 是否可行,每次枚举边权转移即可。状态数是平方级别。

    *17.Codeforces Round #532 (Div. 2)

    D

    题意:交互题。999*999的平面上有666个黑点,一个白点。每回合白点每次只能移到周围八个格子上;挑一个黑点移动到任意空白处。若白点和某个黑点同行或者同列那么白胜,2000回合后白不胜则黑胜。白先。你执白,要通过移动达成胜利。

    key:交互

    E

    题意:给一个无向图带权,你需要反转一些边的方向使其没有环,问反转的最大边权最小是多少,并给出一个方案。 (n le 10^5)

    F

    题意:给 n 个数,q 次区间查询,每次询问区间内选出一些点使其异或最大。 (n le 5*10^5)

    key:线性基

    *18. Educational Codeforces Round 62 (Rated for Div. 2)

    E

    题意:长度为 n 的序列,每个点被填上了 [1,k] 的数字或者为空。一个合法的序列为它的任意长度大于1且为奇数的子区间不是一个回文串。问给空格子填上 [1,k] 的数字使其合法的方案数。 (n,kle 2*10^5)

    key:组合数学,dp

    可以发现一个合法的序列是不存在长度为 3 的回文串。即将相邻奇数项不同且相邻偶数项不同。奇偶拿出来分别做。

    现在问题变成了对于一个序列,前后可能有一个数字,问有多少种方案使没有相同数字相邻。前后没有数字就是 bzoj 的越狱。有一个也差不多,关键在于前后都有数字。

    只需要设 (f_{i,0/1}) 表示长度为 i ,前后不相同/相同的方案数。讨论在一端填数字的状况即可转移。复杂度 O(n)

    F

    题意:二维平面上 n 次操作,支持插入一个点、删除一个点、求 (E(S)) 。其中 S 是点集, (E(S)) 定义为 S 中按规则加入若干点后得到的点集大小(只做询问不实际加入)。规则为:若已存在三个点构成一个平行坐标轴的矩形的三个角,则把剩下那个角的坐标加入点集。 (n le 10^5)

    key:线段树,带撤销并查集

    新姿势。

    先考虑给定点集如何求 (E(S)) 。考虑点 ((x,y)) 何时被计算进答案的充要条件,当且仅当点集中既有横坐标为 x 的点也有纵坐标为 y 的点。换句话说,若将横坐标相同和纵坐标相同的点之间连边,得到的每个联通块的答案是联通块内不同的横坐标个数*不同的纵坐标个数。

    进一步发现,若将横纵坐标看成点,每个点看做对应横纵坐标之间连一条边,则答案就是每个联通块内横坐标点数*纵坐标点数。所以可以用并查集维护。

    问题在于如何删除。可以预处理出来每条边出现的时间段,对时间建一棵线段树,线段树每个点存储覆盖该区间的边,然后对其dfs,进入则插入边,回溯则删除边,到叶子计算答案。于是只需要带撤销并查集即可。复杂度 (O(nlognalpha(n)))

    *19. 2018-2019 ACM-ICPC, Asia Nanjing Regional Contest

    BFHL

    C

    题意:二人在树上博弈,初始所有点都无色。A 选一个点染粉,B 选一个点染棕,A 再选一个点染粉,然后游戏结束。此时 A 的得分为到达棕点路径上存在粉点的点数, B 想最小化,A 想最大化,问最终 A 的得分。 (n le 10^5)

    key:树上博弈,树的重心

    先让 A 的第一步随便选一个点 u,此时 B 会挑 u 的一个子树的重心 v, A 会将其最大的儿子砍掉。此时得到一个解。

    所以关键在 A 的第一步到底选的哪个点。由于 A 想最大化得分,所以在此基础上要趋向于得分更多的策略。若 A 将第一步选择的点向远离 v 的方向移动,则 B 保持原来的策略,得分只会变小(因为经过第一个粉点的点变少了,而第二个粉点至多弥补)。故 A 只会把 u 向当前的 v 靠近。

    于是有一个分治思路:对第一个选的点分治,O(n) 得到当前点的答案。由于至多分治 log 次,总复杂度 (O(nlogn))

    E

    题意:给两个长度为 n 的 01 串 s 和 t,每次操作是将连续长度为 m 的 1 或 0 翻转。问 s 是否能经过若干次操作后变成 t。 (len le 10^6)

    key:智商

    首先发现操作是可逆的。

    然后发现实际上操作是将连续 m 个 1 变为 0 或者将一个 1 连续走 m 步,并且不能越过其他 1。

    于是可以将两个串的 1 都向前挪,达到 m 个就消去,最后检查是否相同即可。

    M

    题意:给两个串 s 和 t,要求选择 s 的一个子串与 t 的一个前缀首尾相连,使其是回文串,问方案数。 (len le 10^6​)

    key:manacher,z算法

    将 s 倒过来,即求 s 的一个子串与 t 的一个前缀相同,并且子串前面紧跟一个回文串。用 z 算法做一遍匹配,枚举回文串,该回文串的贡献就是以 [i+1,i+r[i]] 作为开头与 t 的前缀匹配的字符串数,这个可以前缀和一下。于是总复杂度是 O(n)。

    *20. 2018-2019 ACM-ICPC, Asia Nakhon Pathom Regional Contest

    BI

    A

    题意:给 n 个数,每个数表示一个杆子的高。可以从一个高杆子跳到低杆子上,途经和终点的杆子高度不能超过起点。每次询问从 x 开始最多可以跳多少次或者从 x 跳到 y 最多可以跳多少次。 (n le 10^5)

    key:笛卡尔树

    如果数字互不相同,显然就是笛卡尔树的子树深度/深度差。考虑相同数字。

    笛卡尔树可以建成相同数字组成一条右儿子链。

    需要维护的东西是一个点到根经过的不同数字最多是多少,记为 (ans\_from\_root[u]​) 。还需要维护从该点向下经过不同数字最多是多少,记为 (ans\_from\_this[u]​) 。前者很好维护,后者需要维护一个 (tmp[u]​) 表示 u 子树中 (ans\_from\_this[u]​) 最大是多少。这样如果是从和当前点权值相同的儿子转移而来(一定是右儿子),则需要用右儿子的左儿子的 tmp 来更新 (ans\_from\_this[u]​) ;否则直接用 (tmp[u]​) 更新。

    询问从 x 开始最多可以跳多少次,直接输出 (ans\_from\_this[u]) 。否则,设 y 在 x 的子树内。x 不能跳到 y,当且仅当有一个与 x 点的高度相同的杆子挡住,即 x 的右儿子和 x 权值相同且 y 在这一分支之内。

    讨论清楚之后,一遍dfs即可。

    *21. 2018-2019 ACM-ICPC, Asia Dhaka Regional Contest

    ADGI

    G

    题意:简化后为给一棵树,多次询问 u 到标号在 [l,r] 的点集中最近的距离是多少。

    key:点分树

    建出点分树,套个线段树,按标号排序,维护距离最小值。

    22. 2018 German Collegiate Programming Contest (GCPC 18)

    差个 G ,快乐。

    23. Codeforces Global Round 2

    F

    题意:给一棵带权树,定义 f(x) 为删去若干边后使得每个点度数小于等于 x 且删去边集权值和最小是多少。求 f(0) 到 f(n-1)。 (2le n le 2.5*10^5)

    key:树形 DP,堆

    考虑单组询问: (f_{u,0/1}) 表示将 u 子树中删去若干边,并且节点 u 的度 (le x) / (le x+1) 的答案。对于转移,每次考虑删掉哪些边,可以按 (val_v+f_{v,1} - f_{v,0}​) 排序选择最小的若干个,剩下的不删。

    对于多组询问,考虑按 x 升序做。每次只考虑度数 > x 的点,设其是 good。每次只考虑 good 点形成的森林。

    所有点的度数之和是 2*(n-1)。所以对于所有的 x ,good 点总数就是 2*(n-1) 。

    对森林里每棵树做 dp。u 的儿子可能是 good 也可能不是 good。对于 good 的点,按单组的做法排序;对于不是 good 的点,直接按边权排序。每次就是拿出权值最小的若干个转移。对于树边可以直接遍历,非树边可以用一个权值线段树维护(插入一个点,查询前 k 小的权值和)。

    当 x 变大时,只有可能 good 点变成非 good ,所以将其丢到线段树即可。

    总复杂度 (O(nlogn))

    G

    题意:有 n 个人,需要打 m 个阵营,每个阵营有 (a_i​) 个血,你需要先把 n 个人划分成 m 个小队,每回合指定某个小队攻打某个阵营(可以多打一),每个阵营减血量是攻打他的人数之和。目标是让敌方每个阵营的血量小于等于 0。构造出一组划分方案使得回合数最少,并输出每回合攻打策略。 (1le mle n le 10^6​)

    key:构造,智商

    回合数至少是 (frac{sum a_i}{n}​) 上取整,考虑什么时候会取到这个数。首先把所有的 (a_i​) 对 n 取模。

    考虑攻打第一个,最优情况下我方恰好有某些小队总人数就是 (a_1​) ,剩下的攻打第二个,那么我方剩下的恰好有某些小队总人数就是 (a_2​),直到最后一个。若前面的都恰好凑出来,则最后一个不需要恰好,此时回合数就是上面的那个值。

    可以设 a 的前缀和对 n 取模,排序后取差分。此时每个需要恰好凑出来的数字都对应了一个区间,并且按下标首尾相接,于是从第一个开始攻打即可。

    H

    题意:给 n 个数组,每个数组中有 x 个 (a_i​) ,y 个 (b_i​) ,z 个 (c_i​) 。要求每个数组中取出恰好一个数将其异或起来。问得到 i 的方案数是多少。求所有的 i 从 0 到 (2^k-1​)(n le 10^5 ,k le 17​)

    key:FWT

    fwt 复习题。

    首先一个暴力做法是构造 n 个长度为 (2^k​) 的数组,做 n 遍 fwt,其中每个数组中只有至多三个非零元素: (F_i[a_i]=x,F_i[b_i]=y,F_i[c_i]=z​) 。下面开始复习 fwt。

    因为 fwt 是线性变换,即变换后的每个元素是变换前的 (2^k​) 个元素的线性组合。由于本题只有三个非零元素,并且是异或的 fwt ,所以线性组合的系数是 1 或 -1。

    fwt 对异或的变换为 (f_i = sum_j (-1)^{count(i&j)}a_j​) ,其中 (count(x)​) 为 x 的二进制中 1 的个数。

    若变化为 (F_i[0]=A,F_i[b_i xor a_i]=B,F_i[c_i xor a_i]=C​) ,则可以发现每个数组经 fwt 后只有四种元素:(A+B+C,A+B-C,A-B+C,A-B-C​) 。最终答案需要异或所有 (a_i​) 作映射。

    于是对于第 i 位,若以上四种元素在所有数组的第 i 位中出现次数分别是 (x,y,z,w​) ,则答案为 ((A+B+C)^x*(A+B-C)^y*(A-B+C)^z*(A-B-C)^w​) ,现在的问题是确定 (x,y,z,w​)

    其实若 (F[0]=A,F[b]=B,F[c]=C,F[c xor b]=D​) ,则由 fwt 对异或的变换可知变换后的数组只包含 (A+B+C+D,A+B-C-D,A-B+C-D,A-B-C+D​) 这四种元素。

    (B=1,A=C=0)(C=1,A=B=0) 以及 (F_i[b_i xor c_i]=1) 可得三个线性无关方程,以及显然的 (x+y+z+w=n) 。现在有四个方程,可以解出每一位的 (x,y,z,w)。最后再做一遍 fwt 逆变换即可。

    其实这个做法很容易拓展,可以出 m 个非零元素,或者运算不是异或。

    *24. 2018-2019 ACM-ICPC Southeastern European Regional Programming Contest (SEERC 2018)

    A

    D

    题意:给一颗树,需要从 1 遍历每条边至少一遍之后回到 1,可以花费权值的时间走边或者花费时间 k 跳到另一个点上。至多跳 m 次,问花费时间最少是多少。 (n,m le 1000)

    key:树形dp

    如果不跳,那么一定是每条边走两遍。

    如果跳,那么可以认为跳过的路径上的所有边都只走了一遍,剩下的是两遍。手玩可得,如果一条边被覆盖了两次那么还是要走两遍。换句话说,被覆盖奇数次的边走一遍,偶数次的边走两遍。无论怎样,都会存在一条回路使得其能回到 1。

    于是一次跳只关心两个端点的位置,不妨设其为 good 。

    (f_{i,j}​) 表示 i 子树内有 j 个 good 点的最小代价。若 j 是奇数那么 i 的父边计算一次,偶数则计算两次。做完之后再加上跳的代价即可。

    H

    题意:n 个人, m 个愿望,每个愿望形如 x 希望 y 不开心。x 开心当且仅当他希望的不开心的人中有一个真的不开心。你需要实现至少 m/4+1 个愿望,保证有解,输出一种方案。 (n le 10^5 , m le 2*10^5)

    key:随机

    随机每个人开不开心然后check,可过,飞快。

    K

    题意:每次在二维平面上添加一个点或者一个矩形,每次操作后问有多少个 <点,矩形> 对满足点被矩形包含。 (n le 10^5)

    key:cdq 分治

    把矩形转化为前缀,就是二维偏序问题,直接上 cdq 分治。

    25. Educational Codeforces Round 61

    E

    题意:有一个容量为 W 的背包,有 8 个物品,体积为 i 的物品有 (c_i) 个, (1 le i le 8)。问背包最满可以装多满。 (0 le W le 10^{18}, 0 le c_i le 10^{16}​)

    key:背包

    取 1 到 8 的 lcm,设为 L,其值为 840。

    发现如果一个物品 i 拿的数量大于等于 L/i ,则可认为是拿了一个体积为 L 的物品,于是每个物品只需要选小于 L/i 个,剩下的都凑成 L 。

    于是只需要枚举每种物品拿了多少个,剩下的全部凑成 L 的物品。 (f_i) 表示拿了总共为 i 的体积的物品,剩下的凑成的 L 的物品最多是多少,做一个 01 背包即可。 i 需要取到 8L。

    *26. 2018-2019 ACM-ICPC, Asia Jiaozuo Regional Contest

    BCGKL

    J

    题意:给 n 个矩形,覆盖在 (m cdot m) 的二维平面上。删掉恰好两个矩形,使得被覆盖的点数最少,求最小值。 (n le 3*10^5, m le 1500)

    key:骚操作

    考虑所有被覆盖一次和两次的点,答案只有可能是覆盖它们的矩形。

    现在问题在于如何找到覆盖当前格子的矩形是哪些,该点至多被覆盖两次。

    维护两个前缀和:子矩阵加 i ,子矩阵加 i*i 。这样就知道了 (a+b)(a^2+b^2) 的值,解方程即可。

    *27. 2012-2013 ACM-ICPC, NEERC, Moscow Subregional Contest

    BDH

    J

    题意:给 n 个物品排序,权值不满足传递性,要求相邻两个满足偏序关系。每次可以询问两个元素谁大谁小,要求总询问数不超过 10000. (n le 1000)

    key:交互,排序

    相当于 cmp 函数调用次数不超过 10000 。sort不是稳定排序,归并是稳定的,所以需要用 stable_sort。这样排出来即使不满足传递性也是合法的。

    28. Forethought Future Cup - Elimination Round

    E

    题意:有 n 个数,每次操作形如:把所有大于/小于 x 的数字乘 -1。问 m 次操作后的最终序列。 (n,m le 10^5)

    key:线段树

    开值域线段树,每个点维护该值是否被翻过。按大于/小于号和 x 的正负四种情况讨论,发现只需要维护区间翻转和区间赋值即可。

    G

    题意:有 n 个位置,每个位置可以设定一个高度,最高为 h。一个位置的高度为 x 则可以获得 (x^2) 的价值。有 m 个区间,每个区间有一个设定高度,若区间内存在一个位置的高度超过设定高度,则需要付出 (c_i) 的代价,求总价值和最大。 (n,h le 50)

    key:区间 dp,最小割

    其实是两个算法都能做……

    区间 dp

    (f_{i,j,k}) 表示区间 ([i,j]) 最高高度小于等于 k 的最大价值。每次枚举中间点,认为它的高度就是 k,然后枚举被完全包含在该区间的限制,复杂度 (O(n^5))

    最小割

    首先转补集,即不选的高度最小。

    每个位置拆 h 个点表示选的高度, ((i,j)) 连向 ((i,j+1)) 流量为 (h^2-j^2) 表示选高度为 j 的价值。设一个限制为 ([l,r]) 最大高度超过 x 则付出 c 的代价,则新建一个点 p ,所有区间内的高度为 x+1 的点向 p 连正无穷的边, p 向汇点连 c 的边。源点再跟所有高度为 0 的点连边。

    对于正确性,考虑割的情况:如果割了某个限制的边,则表明有权值大于等于这条边的位置,即区间内已经有超过了高度为 x 的限制,那么它会继续向后。 若割了某个 (h^2-j^2) 的边,表明该位置的高度小于等于 j 。

    *29. Codeforces Round #554 (Div. 2)

    F1 F2

    D

    题意:求长度为 2*n 的所有合法括号序列形成的 trie 中最大边独立集大小,取模。 (n le 1000)

    key:dp

    由于要取模,所以这个题不能直接dp,先找一下规律。

    贪心策略:设根节点为 0 ,只拿以奇数层点为父亲的边。

    考虑从下到上。由于叶子只在最后一层,那么如果有一个奇数层的点不选,那么肯定选它上面的一个点,这对上面造成的限制会更大,答案不会变优。

    E

    题意:有一个长度为 n 的序列 a ,构造 b 和 c 序列为:a 的相邻两项的最大值/最小值,长度为 n-1 。然后再按同样的排列对 b 和 c 作置换。现在给 b 和 c,求 a。 (n le 10^5)

    key:欧拉路

    (b_i)(c_i) 一定相邻,所以连边跑欧拉路即可。不合法就判一判。

    30. Codeforces Round #553 (Div. 2)

    F

    题意:求无向图中最少留下多少条边使得整个图是双连通图。输出方案。 (n le 14)

    key:状压 DP

    双连通图的组成:一个双连通图和一个点/一条链连起来。所以预处理链,然后转移,复杂度 (O(n^23^n))

    31. Codeforces Round #551 (Div. 2)

    F

    题意:在 [0,l] 之间随机选 n 个线段(每个线段的随机方式是随机两个实数端点),问被覆盖大于等于 k 次的总长度期望是多少。 (n,k le 2000)

    key:DP

    只需要考虑在 [0,1] 之间随机。被覆盖大于等于 k 次的总长度期望即为再随机选点 P 落在被覆盖大于等于 k 次的点的概率。由于实数上随机,所以可以认为所有点互不相同。现在问题变为点 P 被覆盖大于等于 k 次的概率是多少。

    (f_{i,j,x}) 表示放了 i 个点,当前还有 j 个左端点没有合口,P点放没放的概率。每次考虑当前点放哪种点即可。最终答案为 :

    [frac{f_{2*n+1,0,1} * n! * 2^n}{(2*n+1)!}*l ]

    *2018-2019 XIX Open Cup, Grand Prix of Korea

    BCJK

    D

    题意:给 n 个人排队,要求第 i 个人必须在区间 ([l_i,r_i]) 内,且给定 m 组 (u_j) 必须在 (v_j) 之前的关系。 (n,m le 3*10^5)

    key:拓扑排序

    显然对于每个 ((u_j,v_j)) 的关系,他们的区间边界满足 (l_{v_j}=max(l_{v_j},l_{u_j}+1))(r_{u_j}=min(r_{u_j},r_{v_j}-1)) 。拓扑排序之后可以对每个点做一次这种操作。对于这样得到的区间,考虑这样的贪心:从左往右扫,每次选可选的区间中右端点最靠左的。这样保证当有限制关系的区间同时可选时,一定选了前驱,这样排出来的就是正确的。

    G

    题意:有 n 个格子,每个格子有一个灯,每个灯打开有一定花费,一盏灯可以照亮它本身和它的前后一格。你可以交换 k 次两个灯的位置,求照亮所有格子的最少花费。 (nle2.5*10^5, kle 9)

    key:DP

    考虑交换后的最终序列,它的最优解中打开的那些灯。可以发现在最优解中,一定不存在交换了两个灯,使得两个灯最终都灭/都亮,所以一定是交换了若干对,每对在最优解中一个灭一个亮。

    所以只需要挑出至多 k 个灯设定它们是灭的,再挑至多 k 个灯设定它们是亮的,剩下的普通 dp 即可。

    (f_{i,a,b}) 表示前 i 个灯,已经挑出了 a 个亮的灯,b 个灭的灯,且第 i 个灯是亮的的答案。每次转移到下一个亮的灯 (j (j le i+3)) ,需要讨论 j 的灯需不需要挑出来、中间夹着的灭的灯需不需要挑出来。

    最后计算答案,需要在末尾添加一个 INF 的灯,再添加一个 0 的灯。这样是目的是保证所有点都考虑过是否挑出来了。

    M

    题意:带边权的树,挑出恰好 k 条边使其互相没有交点且边权和最大。 (k<nle 2.5*10^5)

    key:树形 DP,wqs 二分

    设恰好选 y 条边的最大权值是 (f(y)),容易发现 (f(y)) 的差分随着 y 增大而减小,即形成了一个凹函数(上凸)。此时便可以用 wqs 二分。

    给每条边加一个代价 x,发现选的边数与 x 的大小成正比。于是二分 x,做 O(n) 的 DP 即可。

    要注意两点:当有多解时,选选的边更多的方案。在这个前提下,当没有结果恰好是 k 条边时也无妨,答案需要是第一个 >=k 的值减去 k*mid 。

    下面简单说一下证明。二分 X 得到的是 f(y)+yX 。若不存在结果恰好是 k 条边的情况,则必有 (f(k)+kX=f(l)+lX) ,其中 (l) 是二分得到的满足选边大于 k 的最小选边数。此时用等式右边减去 kX 就是所求答案。

    其实这种情况说明 (f(y)) 在 k 附近的斜率相同,都是 -X。此时加上一个斜率为 X 的直线会形成水平的情况。

    J

    题意:给 n 个数,求 (F_{i,j}=(i-j+1)*min_{iin [i,j]}a_i) 的第 ([L,R]) 小是多少。 (n le 3*10^5, L_i le R_i le frac{n(n+1)}{2}, R-L+1 le 3*10^5)

    key:堆,求 k 小

    求第 L 小:二分。此时知道了以每个点为最小值的最小区间长度是多少。将其加入堆里,每次取最小的。

  • 相关阅读:
    what's the python之异常处理
    what's the python之面向对象(进阶)
    what's the python之面向对象
    what's the python之自定义模块和包
    Java并发编程-并发工具包(java.util.concurrent)使用指南(全)
    Java之JUC系列:外部Tools
    java CS结构软件自动升级的实现
    史上最全最强SpringMVC详细示例实战教程
    搭建最简单的SpringMVC框架(使用maven)
    小心对待query_cache_size
  • 原文地址:https://www.cnblogs.com/dqsssss/p/11144694.html
Copyright © 2020-2023  润新知