zoukankan      html  css  js  c++  java
  • 好题记录

    2019.6

    Codeforces 1166C A Tale of Two Lands

    给定一个数列,求其中满足 (min{|x+y|,|x-y|} leq min{|x|,|y|})(max{|x|,|y|} leq max{|x+y|,|x-y|})的数对((x,y))个数。
    (n leq 2 imes 10^5)

    如果去分类讨论(x,y)的符号会把问题变得非常复杂。观察条件包含的性质,发现这个条件是与((x,y))符号无关的。也就是说如果将所有数都取其绝对值不会影响答案。

    只需要考虑非负数的情况,那么排序之后对于每个(x)求出(y)的取值范围二分统计一下即可。复杂度(O(n log n))

    Codeforces 437 C. The Child and Toy

    给出一个带点权的无向图,每次选择一个点删除,并删除这个点所连的边。删除一个点的代价是此时其所有相邻点的权值之和。问删完所有点的最小总代价。

    (n leq 1000, m leq 2000)

    删点的实质是在删边,每条边都会被删一次。正向反向考虑都很难,我们考虑每条边被删除时对答案产生的贡献。每条边被删除时它的两个端点中其中一个产生贡献。为了让答案尽量小,不妨假设每次都是点权较小的那个产生贡献。这就要求对于每条边都要先删除点权较大的点。这样做是否是可行的?如果我们能构造出一个删点顺序满足这样的条件那就是可行的。每条边都规定了一个顺序:点权大的排在点权小的之前。我们可以将每条边看做一条有向边,从点权大的连向点权小的。

    这样形成的图一定无环(暂不考虑点权相等的情况),因此一定可以拓扑排序,那也就是说这样的方案一定存在。

    而点权相等就可能有环,不过环内点先后是无所谓的。

    因此枚举每条边即可求出答案,复杂度(O(m))。为什么数据范围出那么小= =。

    Codeforces 1165 E. Two Arrays and Sum of Functions

    给出两个长度为(n)的序列(a)(b),定义(f(l,r)=sumlimits_{i=l}^ra_ib_i)。现在可以给序列(b)中的元素指定任意顺序,问怎样指定(b)的顺序能让(sumlimits_{1 leq l leq r leq n}f(l,r))最小。

    (n leq 2 cdot 10^5)

    我们考虑对于每一个位置(i)(a_i cdot b_i)会被统计(i(n-i+1))次。

    因此答案可以用这种形式来表示:

    [sumlimits_{i=1}^na_ib_i imes i(n-i+1) ]

    这个式子中除了(b_i)之外都是只与(i)有关的定值,因此考虑设一个(c_i=a_i imes i(n-i+1)),答案转化为求(sumlimits_{i=1}^nb_i c_i)的最小值。

    这个问题也就是给你两个序列(a,b),问怎么给它们排列顺序能使(sumlimits_{i=1}^{n}a_ib_i)最小。

    关于两个序列两两相乘之和最小,有一个贪心的结论:(a)从小到大排序,将(b)从大到小排序,(a_i)配对(b_i),这样一定使答案最小

    证明:

    对于(a_i,a_j,b_i,b_j)(排序后的)满足(1 leq i < j leq n)。仅考虑这两项,现在的结果是(a_ib_i+a_jb_j)。如果交换(b_i,b_j),那么答案是(a_ib_j+a_jb_i)。作差可得

    [a_ib_i+a_jb_j-a_ib_j+a_jb_i=a_i(b_i-b_j) + a_j(b_j - b_i) = (a_i-a_j)(b_i - b_j) leq 0 ]

    因此不交换一定不会劣。

    拓展:如果要使(sumlimits_{i=1}^na_ib_i)最大,那么结论是将(a)(b)都从小到大排序配对。证明类似。

    Codeforces 276 D. Little Girl and Maximum XOR

    给出(l,r),求(max{ a oplus b } (l leq a leq b leq r))

    (1 leq l,r leq 10^{18})

    先将(l,r)转二进制。位运算中要使某个数尽量大一定是从高位开始贪心。从最高位开始,如果相同也没有办法凑出(1)。直到第一个不同的位,我们能够凑出(1)。从这以后因为第一位已经不同的,于是(b)中每一位都可以变成(0)而不必担心小于(a)(a)的每一位都可以上升而不必担心大于(b)。因此后面的每一位都可以凑出1了。

    Codeforces 577 B. Modulo Sum

    给出(n)个数,问能否选出一个子集使得其和能被(m)整除。

    (n leq 10^6, m leq 10^3)

    (n)个数做前缀和(s_i),然后将(s_i)(m)取模。如果存在(s_i=s_j)则区间([i+1,j])内数的和是(m)的倍数。根据鸽巢原理,只要(n>m)就一定存在这样的区间。

    于是限制条件就变成了(n leq 10^3)。直接做背包即可。

    Codeforces 552 C. Vanya and Scales

    给出两个数(w)(m),并给出(101)个砝码(w^0,w^1,cdots,w^{100})(每种重量只有一个)。将(m)放在左边,现在要在左右放若干砝码,问是否可能平衡。

    (1 leq w,m leq 10^9)

    每个砝码可以放左边,放右边,或不放。也就是每个砝码的系数为({-1,0,1}),问是否能使其总和为(m)。显然(w=2)一定满足,从(w=3)开始考虑,(log_310^9 approx 20),因此折半搜索。

    Codeforces 578 B. "Or" Game

    给出一个序列,可以进行(k)次操作,每次可以给序列中的一个数乘一个定值(x)。问操作后所有数的最大或和。

    (n leq 2 imes 10^5, k leq 10)

    任何一个数乘上一个(>1)的数二进制一定左移一位。有了这个结论把(k)(x)数乘在同一个数上一定最优。

    2019.7

    Codeforces 1019 A. Elections

    (n)个人给(m)个党投票。可以花(c_i)贿赂第(i)个人改变投票对象(任意改变),否则第(i)个人就会投票给(p_i)党。问最少花多少钱能让(1)党获胜。
    (1 leq n,m leq 3000)

    不确定得票时很难求。考虑枚举(1)党得票,贪心计算最少花费。复杂度(O(n^2))

    Codeforces 442 B. Andrey and Problem

    (n)个人,第(i)个人有(a_i)的概率同意,(1-a_i)的概率不同意。请从这些人中选择一些人,使得其中只有一人同意的概率最大。问最大概率。

    (n leq 100)

    假设我们已经选择了一个集合(S),则概率为(sumlimits_{i in S}left (a_i dfrac{prodlimits_{j in S}(1-a_j)}{1-a_i} ight))

    (A=prodlimits_{i in S}(1-a_i))(B=sumlimits_{i in S}dfrac{a_i}{1-a_i})。则概率为(AB)

    考虑加入一个(a_k)后答案的变化量

    (Delta=(B+dfrac{a_k}{1-a_k}) cdot A cdot (1-a_k)-SB=A(1-B)a_k)。因此只要满足(1-B>0),那么选择(a_k)就能使答案变大。贪心地,我们从大到小选择(a_k),直到(B geq 1)为止。

    复杂度(O(n log n))

    Luogu P2336 喵星球上的点名

    (n)个人,每人有两个字符串。给出(m)次询问,每次询问给出一个字符串,问这个字符串在多少个人的那两个字符串中的一个里出现过。询问结束后输出每个人被询问到的次数。

    (n leq 5 imes 10^4, M leq 10^5)

    (SA)后问题转化为区间颜色个数,与每个颜色被覆盖的次数。前者直接用莫队解决,后者考虑差分:每次覆盖到,就对答案加上剩余询问个数次贡献,每次离开,就对答案减去剩余询问个数次贡献。

    Codeforces 375 B. Maximum Submatrix 2

    给出一个(01)矩阵,可以任意交换行的顺序。求交换后可能的最大全(1)子矩形面积。

    (1 leq n,m leq 5000)

    如果不能交换行,直接单调栈解决即可。

    交换行之后每行的排列还是确定的。由于面积没有特殊的性质,我们考虑枚举矩形一条竖边的位置,为了最大化面积,我们将所有行按照每行该位置向右扩展1的最大距离排序,很容易计算面积。复杂度(O(n^2 log n))

    Codeforces 2 B. The least round way

    【双价值的处理】给出一个(n cdot n)的矩阵,从左上角走到右下角(向右或向下),经过的数字相乘。怎样走使得得到的结果结尾的0尽量少。

    首先处理出每个数的2因子与5因子个数。接着有个重要结论:结尾的0的最小个数,为最小2的路径与最小5路径中的较小值。这样就把双价值的问题转化为单价值的问题了。

    反思:双价值总是难以处理的。

    Codeforces 463 D. Gargari and Permutations

    【建图;问题特性】给出(k)个长度为(n)排列(1 leq n leq 1000,1 leq k leq 5)),求出LCS。

    枚举数对。预处理出每个数对在每个排列中是顺序的还是逆序的。如果对于所有排列某数对都是同一个序的,那么这个数对就是可以作为LCS的一部分的。找出所有这样的数对之后,得到一张(DAG),求出最长链即可。

    反思:DP的本质是DAG。因此关键是要抓住这张DAG在这里是什么。

    Codeforces 449 B. Jzzhu and Cities

    【建图;最短路的性质】给出一张带权的无向图。再给出(k)条长度(w_i)((1,r_i))的路径。问这(k)条路径最多能删掉几条,使得删掉之后所有点到1的最短路不变。

    将这(k)条路径加入图中,跑(Dijkstra)。同时每个点统计一个最短路入度。然后依次这(k)条路径,如果长度大于相应的最短路那肯定删去。如果恰好等于,那么看最短路入度,大于1则可以删去。然后将最短路的入度减去1.

    反思:这其实是一个最短路树(最短路图)的问题。删边问最短路变化的问题一般都这样处理。

    Codeforces 471 D. MUH and Cube Walls

    【字符串差分匹配】修改字符换匹配的定义:两个字符串的所有字符的差都相同。问匹配数。

    我们来分析一下这样匹配有什么特殊的性质,发现他们两两相邻的差是一样的。于是我们可以预处理出两个串的差分数组,然后直接去匹配差分数组就可以了。用KMP算法(O(n))完成就可以了。

    反思:匹配的本质就是寻找相同的东西。在这里两个数组相同的东西就是差分。

    Codeforces 1156 C. Match Points

    给出一个长度为(n)的序列(a)和一个数(z),数对(1 leq i < j leq n)称为一个匹配当且仅当(|a_i-a_j| geq z)。序列中一个数只能匹配一次。问最多能有多少个匹配。

    想到了一个贪心,排序后从前往后匹配差值第一个大于等于(z)的。然而被叉了,对于一个右端点在另一个左端点左边的情况,交换一下更优。

    事实上可以二分答案,而贪心地验证是可以做到的。一定是去选择两端的依次匹配最优。

    反思:直接贪心不可行,也许应用到二分验证中是可行的。

    Codeforces 274 B. Zero Tree

    给出一棵树((n leq 10^5)),有点权(v_i)。每一次操作可以选择一个包含根节点的连通块,使连通块内所有点的权值+1或-1。问最少进行多少次操作才能使整棵树的所有点权都变为0。

    根据题意分析,要对一个点进行操作的话必须对它的所有祖先进行相同的操作。而既然这样,想让一个点的点权归零进行操作,那之前就必须已经完成所有其后代的归零操作(因为如果后代没有归零,以后再去操作后代就必定会影响祖先使得决策不优)。而这样就将问题分解为子树上的子问题了。

    我们记录(up_i)(down_i)表示子树(i)归零所需要的+1与-1的最少操作次数。子树与子树之间可以通过根节点一并操作。这样根节点的权值在操作子树时至少会变化(max{up_v}-max{down_v}),之后再让根节点归零再进行(|v_u+max{up_v}-max{down_v}|)次操作。

    2019.8

    Codeforces 295 E. Yaroslav and Points

    给出一个序列(a_i),((|a_i| leq 10^9)),单点修改。询问给出(l,r),求(sumlimits_{i=l}^{r}sumlimits_{j=i}^{r}(x_j-x_i))

    按照权值建线段树(动态开点或离散化),接下来询问的可以看做线段上两两之间的距离之和。分治求解可以得出两边内部两两的距离,于是只需要计算出所有跨越两边的点之间的距离之和就可以了。既然这样,就可以通过维护区间和以及区间点个数求解了。

    洛谷5154 数列游戏

    给出(n)个物品排成一排,第(i)个物品有两个值(a_i)(b_i)。每次可以选择两个(a)值不互质的相邻物品移除,并获得他们(b)值之和的得分。问最多能得分多少。((n leq 800))

    直接区间DP并不好处理。我们可以先做一次可行性DP,(f_{i,j})表示([i,j])是否可行。(f)的转移有两种:一是枚举中断点;二是两端匹配。复杂度(O(n^3 cdot log))

    处理出来后,再DP一次。(g_i)表示前(i)个的最大得分,分为(i)选与(i)不选,(i)不选直接继承,(i)选可以枚举左端点转移。复杂度(O(n^2))

    HDU 6601 Keen On Everything But Triangle

    给出(n)根木棍(a_i),每次询问一段区间([l,r]),问其中是否存在能拼成三角形的三根,并输出其周长的最大值。(n leq 10^5,a_i leq 10^9)

    考虑对于一些木棍,要使能拼成三角形且周长最长,一定是选择权值相近的三根。因此一个思路是将木棍排序,然后从大到小枚举连续的三根判断能不能拼成三角形。也可以不排序,每次用主席树维护区间第(k)大进行判断。

    这样的复杂度是(O(nm log n))。但由于(a_i leq 10^9),要让一个木棍集合不可能形成三角形并使集合大小尽量大,这样一个集合就是斐波那契数列。而斐波那契数列到第(50)项就超过(10^9),因此我们从大到小最多枚举(50)次一定会有解,并且一定是最优的。依然用主席树来维护。复杂度(O(50m log n))

    Codeforces 675 C. Money Transfers

    给出一个长度为(n)的圆环,第(i)个位置有权值(a_i),保证权值和一定为0。每个位置的权值可以向左或向右转移,问最少转移多少次使圆环上每个位置的权值都是0。

    显然一段长度为(l)的和为0的序列最多转移(l-1)次,因为相互之间你给我我给你可以只做一次。因此我们的任务是求出怎样划分使得和为0的序列尽量多。

    利用前缀和的性质,和为0意味着前缀和的值相等。因此对于每一个前缀和的值用map求出与它相等的值有多少个,巧妙地解决了“环”的问题。

    Codeforces 468 B. Two Sets

    给出(n)个不同数,要将所有数分为两个集合(A,B)。再给出两个数字(a,b),对于任意一个值为(x)的数,如果(x in A),那么(a-x in A);如果(x in B),那么(b-x in B)。输出方案。

    否定后件:如果(a-x otin A),那么(x otin A)。等价于如果(a-x in B),那么(x in B)。也就是说只要(a-x)存在,那么(x)(a-x)必须在同一个集合。同理如果(b-x)存在,那么(x)(b-x)也必定在同一个集合。因此用并查集或者(2-sat)维护即可。

    Codeforces 558 E. A Simple Task

    给出一个长度为(n)的字符串,给出(m)次询问,每次询问给出一个区间([l,r]),将这段区间升序或降序排序。最后输出结果。(n leq 10^5, m leq 5 cdot 10^4)

    考虑用线段树维护区间内每种字母的出现次数。在已知每种字符出现次数的情况下,区间排序等价于(|sum|)次区间覆盖——用线段树维护。

    Codeforces 1200 E. Compress Words

    给出(n)个字符串,每次将第一个和第二个字符串接龙(合并最长前后缀)并合并为一个字符串,输出最终结果。

    每一次合并字符串就需要更新,因此暴力(KMP)的复杂度退化为了(O(n^2))

    考虑字符串哈希,每次在第二个串中从大到小枚举长度,并在第一个串中截取后缀判断哈希值是否相等。

    (hash{s_{l..r}}=a_r-a_{l-1} cdot base^{r-l+1})

    Codeforces 372 D. Choosing Subtree is Fun

    给出一颗树。定义区间([l,r])的权值为包含所有标号$ in [l,r](的点的连通块最小点数。问权值)leq k(的区间最大长度。)n leq 10^5$

    用双指针代替二分答案。那么我们需要动态维护一个连续区间的连通块最小点数。可以将点数转化为边数,那么要求的等价于从根节点出发走遍所有点的最短路径。

    这就是经典的异象石问题。有一个结论:这样的最短路径是所有点按照(dfs)序排序后两两之间的距离之和(最后一个连到第一个)。用(set)维护,支持加点和删点。

    ***「NOIP2017」逛公园

    给出一张有向图,求从(1)(n)路径长度不超过(d+k)的路径条数。其中(d)(1)(n)的最短路。(n leq 10^5,k leq 50)

    难点在于状态的定义。(f[u][k])表示(u)出发到(n)走的弯路长度为(k)的方案数。

    有效路径上的(0)环找起来很讨厌,不会。

    2019.9

    「NOIP2008」双栈排序

    给出一个排列,问其是否能双栈排序。定义进栈比出栈优先,进第一个栈比进第二个栈优先。求字典序最小的操作序列。(n leq 10^3)

    我的第一种思路是直接贪心模拟,然而贪心是错误的。当同时能进两个栈时,有时进第二个栈有解,进第一个栈却无解。

    先来考虑一下单栈排序的情况。对于(i<j),如果(a_i<a_j),说明(a_i)(a_j)先出栈。此时如果存在(j<k)(a_k<a_i),那么(k)必须必(i)先出栈了,这就意味着(k)进栈之前(i,j)都在栈内,也就不能保证(i)先出栈了,因此矛盾。而对于其他情况,(i,j)存在于同一栈内不会矛盾。

    这是一个结论:一个序列不能单栈排序,当且仅当存在(i<j<k)使得(a_k<a_i<a_j)。通过维护最小值,求解的复杂度是(O(n^2))的。

    这就给了我们判断两个元素能否在同一栈内的条件。那么能否双栈排序即判定二分图。然后贪心模拟即可。

    Codeforces 319 B. Psychos in a Line

    给出(n)个人,每个人有一个攻击力(a_i)。每一轮对于第(i)个人,如果(a_i > a_{i+1}),那么(i)就可以杀掉(i+1)。问最少几轮能杀到不能杀。(n leq 10^5)

    这个问题整体考虑比较复杂,可以考虑对于每一个个体来分析它被杀的条件。关键在于,只有相邻才可以杀。因此(i)要被杀,它之前所以比它小的必须死完。定义(f_i)(i)第几轮死,那么(f_i = max{f_j}+1)。用单调栈来维护是(O(n))

    单调栈的优化在于,我可以不用重复统计之前一定比我小的数。在这道题中,我们将一整段比(i)小的信息都存到了(f_i)中,就避免了重复计算。

    Codeforces 1183 E. Subsequences (easy version)

    给出一个字符串,求最长的(k)个本质不同子序列的长度和。(n,k leq 100)

    对于一个字符串,复制一遍之前的本质不同子序列集合,并将新集合内每一个字符串末尾加上这个字符。排序去重,保留前(k)个即可。复杂度(O(n^2k log k))

    Codeforces 280 B. Maximum Xor Secondary

    给出一个长度为(n)的序列(元素互不相同),问所有区间里“最大值异或次大值”的最大值。(n leq 10^5)

    对于考虑所有XX的题目好像都不是直接考虑的。一般都是按每个元素来考虑。

    考虑(a_i)作为次大值:如果最大值在它之前,那么一定是(a_i)之前第一个比(a_i)大的;如果最大值在它之后,那么一定是(a_i)之后第一个比(a_i)大的。

    这一个过程用单调栈来维护即可。

    NOIp2012 开车旅行

    预处理(n)个数每个数,比自己大的最近的和次近的元素。

    以位置为关键字,按照从大到小的顺序将元素插入平衡树((set))中,查询前驱、前驱的前驱、后继、后继的后继四者中离它最近的两个。

    2019.10

    NOIp2016 愤怒的小鸟

    第一象限内有(n)个点,问至少选择多少个形如(y=ax^2+bx 且 a<0)的抛物线能够覆盖所有点。
    (n leq 18)

    在这道题中两点确定一条抛物线,使得状压的转移貌似是(n^2)的,复杂度(O(Tn^22^n))有点悬。

    事实上,我们发现(n^2)转移有些浪费。如果一个转移没有包含第一个点,那么之后迟早要回来转移第一个点。既然这样不如每一次转移包含第一个点的,这样就是(O(n))转移的了。可以将这道题积累为一个优化转移的小(trick)

    SDOI2010 外星千足虫

    给定(m)个异或方程,问最少使用前几个能够解出唯一解。
    n,m leq 2000

    这道题让我联想到了线性基,即先对前(n)个方程进行高斯消元,而后对于每一个方程跟线性基一样插入,直到没有自由元位置。但不知道为什么是不对的。

    题解的做法是直接对(m)个方程做高斯消元。在高斯消元中,第(i)个方程要向下寻找第(i)项系数为1的方程。在这个寻找的过程中记录最大值就是我们的答案。这可以记为一个结论。

    同时,异或方程组由于使用的都是bool数组,可以用biteset优化。

    SCOI2009 最长距离

    给一个01矩阵,同一全0连通块中两点的距离为其欧几里得距离。现可以移去(T)个1,问最远点对距离。
    (n leq 30)

    正难则反。在同一连通块中等价于存在一条没有1的通路。那么枚举点对,判断要使他们连通最少移去多少个1——这个可以用Floyd预处理出来。

    注意点权的Floyd不算起点。

    洛谷4215 踩气球

    给定长度为(n)的序列,并给定(m)个区间。每一次操作时给一个点权值-1,每一次操作后询问有多少个给定区间的和为0。
    (n,m leq 10^5)

    显然复杂度不允许我们每一次操作后遍历所有区间,因此答案的统计得在修改的过程中完成

    考虑用线段树维护区间和。我们知道,一个区间可以拆解为线段树上若干节点。如果这若干个节点的值都为0,那么这个区间的和就为0。

    在这道题中,线段树上一个节点可以作为若干个给定区间拆解后的节点。modify过程中如果碰到一个节点为0,那么就对对应的若干区间产生贡献。如果一个区间被贡献的次数等于拆解后的节点数,那么这个区间和就为0了。

    Codeforces 3 D. Least Cost Bracket Sequence

    给一个由'(','?',')'三种字符组成的字符串。将第(i)个'?'替换成'('的代价为(a_i),替换成')'的代价为(b_i)。问替换成合法括号序列的最小代价为多少。
    (n leq 5 cdot 10^4)

    如果从前往后替换所有'?',那么任何时候右括号数量都不能大于左括号数量。而最后总共能填的左右括号数量是确定的。因此不妨一开始默认将所有的'?'都替换成')'。到达一定程度之后肯定会出现右括号过量的情况,此时需要考虑将之前的某个')'替换为'('。我们贪心地去替换最优的那个,因此用一个优先队列维护之前所有填了右括号的位置。

    Codeforces 1065 F. Up and Down the Tree

    给出一棵树,从一个节点可以跳到子树的一个叶子上,叶子节点可以向上跳,但最多跳(k)条边。问从根节点出发最多能遍历多少个叶子节点。(n leq 10^6)

    一个叶子节点可以直接回到根节点,或者以别的叶子为跳板往上跳,即向上跳(k)格然后到子树内另一个深度更浅的一个叶子再往上跳。

    我们先看从根节点出发能回来的有多少个叶子,这些叶子都跳掉。然后选择一个子树下去……

    从根出发能回来的叶子数量等价于有多少叶子能跳到根。令(f_u)表示从节点(u)为根出发能回来的叶子数量,这样转移:

    [f_u=sumlimits_{v in son_u}f_v[low_v-dep_u leq k] ]

    只要子树最浅的叶子能够到达(u),那这颗子树就不会断节,所有能到(v)的叶子都能够通过这个叶子到达(u);反之就没有叶子能够到达(u)

    答案就是每次统计完(f)之后选择子树往下走,注意如果直接往下走会计算重复。因此在转移(f)的时候,一旦转移成功就将(f_v)清空,能够避免重复。问题转化为求根节点出发的最长链,再(dfs)一遍即可。

    CF1238F The Maximum Subtree

    给出一颗树,要求选出一个(size)最大的连通子图,使得其满足这样的条件:将每个点看做数轴上的一条线段,树上两点之间有边当且仅当对应的线段有交。
    (n leq 3 cdot 10^5)

    分析这个条件,不可能存在三条线段相交于同一点,否则就会形成三元环。因此我们得出结论,答案的树的形态就是一条长的链,链上分出长度为1的边。(即一个毛毛虫)。

    经过化简,答案本质上就是求点权为“度数-1”的最长链。树形(DP)即可。

    洛谷P2371 [国家集训队]墨墨的等式

    给出(a_1..a_n),求(a)基于正整数的线性变换在区间([L,R])内能取到的值得个数。即([L,R])内有多少(B)满足(a_1x_1+a_2x_2+ cdots +a_nx_n=B,x geq 0)
    (n leq 12,a_i leq 5 ast 10^5)

    我们的问题是区间内有多少数能被凑出。我们可以分别求出区间([1,R])([1,L-1])的答案。下面以(R)为例。

    由于加法交换律,我们选定一个(a_i)让它最后加。我们记这个(a_i)(m)。这样的话,一个数(t)能被凑出等价于不用(m)可以凑出(t-k ast m),这等价于(t ext{mod} m)能被凑出。因此我们只需要考虑(m)的剩余系中有多少数能被凑出就行了。可以定义(f(i))为能凑出的模(m)等于(i)的最小数,记为(u)。之所以要最小,因为如果最小答案都(>R)那么就显然无解了。这个过程可以用最短路完成,对于(a_i),我们可以这样转移(f((x+a_i) ext{mod} m) = min{f(x)+a_i})。那么接下来答案就是

    [sumlimits_{i=0}^{m-1}(left lfloor dfrac{R-f(i)}{m} ight floor+1) ]

    洛谷P2939 [USACO09FEB]Revamping Trails

    给出一张无向图,可以将至多(k)条边变成边权为(0)。求(1)(n)的最短路。
    (n leq 10^4,k leq 20)

    由于(k)很小,分层图跑(Dijkstra)即可。

    这道题首先让我联想到了“逛公园”,因此先写了一个(O(nk))(DP)(记搜),但是挂成了(45)。但是我没有写成松弛的形式,不知道有没有这种实现方法。

    Codeforces 280 C. Game on Tree

    给出一棵树,起初所有点都是白色的。每次随机选择一个白点,将它以及它的子树全部染黑。问期望染几次以后树上的点全部被染黑。
    (n leq 10^5)

    期望的线性性质在很多时候能帮助我们拆解问题。比如这道题中,期望的染色次数等于每个点期望的染色次数之和。

    期望是所有情况总和的平均值。我们可以考虑随机一个染色序列,按照这个序列来染色。这样的话,一个点被染色一次当且仅当它的祖先没有一个被染过。

    2019.11

    Codeforces 1225 D. Power Products

    给出(n)个数(a_i)并给出一个定值(k),问有多少对(i,j)能满足(a_i imes a_j = x^k),其中(x)为正整数。
    (n leq 10^5, 2 leq k leq 100)

    容易想到两数乘积是(k)次幂等价于分解质因数后指数之和为(k)的倍数。关键在于怎么统计答案。我们将指数对(k)取模,由此对于每个(a_i)满足条件的(a_j)分解质因数后的形式(指数取模)是可以算出的。所以只要用哈希压缩一个数分解后的表达式,在(map)中查询即可。

    Codeforces 1242 B. 0-1 MST

    给出(n)个点的完全图,其中有(m)条边的权值为(1),其余所有边的权值都是(0)。求原图的最小生成树。
    (n leq 10^5, m leq 10^5)

    我们只看权值为(1)的边。那么可以题型转化为求补图的连通块个数。答案即为连通块个数(-1)

    我们用并查集来维护连通块,问题在于要避免一个点被重复合并。我们用一个类似链表的(nxt)指针,每次暴力合并一段区间,即每个点与它的(nxt)合并,最后一个(nxt)和当前点合并,最后修改区间内所有点的(nxt),这样就能保证每个点不被重复合并了。

    Codeforces 1242 C. Sum Balance

    (k)个箱子,第(i)个中有(n_i)个数。每个箱子中的数已知,保证所有箱子中的所有数字互不相同。现在要从每个箱子中选出一个数,将这(k)个数随意排列后一一放回。问是否存在一种方案使得操作后每个箱子中数的和相同。
    (n_i leq 5 imes 10^3, k leq 15)

    “所有数字互不相同”这个条件非常重要。因此对于一个箱子,选出一个数后应该放入哪个数是确定的。我们考虑连一条有向边(不允许同一盒子内的数相连),这样的话如果存在一个环,并且环上所有点所在盒子互不相同,那么这些盒子都能够达到最终状态了。

    再通过“互不相同”这个条件,一个数只对应一个数,意味着每个点的出边只有一条。因此不会出现环套环。因此我们很容易找出所有满足条件的环。

    并不是每个环都是可选的,我们要选出几个环使得其所在盒子互不相同且并集为全集。由于(k)很小,用刷表法状压即可。

  • 相关阅读:
    最长上升子序列
    system call filters failed to install; check the logs and fix your configuration or disable system c
    linux centos 7 安装vnc远程服务
    Delphi XE 错误提示: [MySQL]-314. Cannot load vendor library [libmysql.dll orlibmysqlld.dll]
    MYSQL 修改密码的几种方式
    MySQL 常用操作和字段类型
    Java 获取GUID
    C# 获取GUID
    C++ 获取GUID
    Delphi GUID[2] 获取GUID值的方式
  • 原文地址:https://www.cnblogs.com/qixingzhi/p/11812111.html
Copyright © 2011-2022 走看看