Contest 6
A
两个数,第 (i) 轮从较大数(如果相等就是第一个)里减去 (i) ,问操作不能进行时两数分别为多少。
首先把大数减到和小数差不多,然后我们会发现接下来两数会轮流减,所以剩下的部分两数各减去的都是奇偶性相同的数。这样的话对两个阶段分别二分答案即可。
B
已知数列 ({a_n}) 的每个数乘上权重 ({c_n}(sum c_i=1)) 后的和(设为 (f(a,c)) ),求数列 ({b_i}) 乘上权重之后的和(设为 (f(b,c)) )的最大值。
我们把它们的式子写出来会发现, (f(b,c)) 与 (f(a,c)) 是有线性关系的,这时我们在每两个点之间连边,答案就转化成了对于一个给定的 (x_0) ,求与 (x=x_0) 相交的线段里最大的 (y) ,然后枚举即可。
C
初始有 (n) 个集合,每个集合里只有一个数,现在需要你依次合并相邻的两个集合,合并的代价是两个集合里大于另一个集合最小值的元素个数,求全部合并的最小代价。
原题体面比较恶心,这个大于另一个集合最小值是转化出来的。首先可以想到一种空间换时间的做法:预处理出最小值和小于某个值的个数,然后直接 (O(1)) 转移区间 (dp) 。但是这样空间会炸得飞起(虽然可以改成short
避免炸空间但还是数据再大一丝丝就炸了),我们需要考虑一种不需要预处理过多东西的做法。对于一个区间 ([l,r]) ,我们换一种方式枚举分界点,从区间最小值开始向右走,显然此时右侧的贡献就是右区间长度,左侧区间可以维护一个堆,分界线每移动一格就将右侧的新数加入,然后将小于右侧最小值(预处理出来)的弹出,此时堆的大小就是左侧的贡献。这样正着做一遍,反着做一遍就可以统计出答案了。还有一个小trick:对于此题数据范围,把堆换成桶可以优化掉一个 (log n) 。
D
给出一个被删去一些数的排列,求使得填数后排列的逆序对数在 ([l,r]) 中的方案数。
直接搜索不行,考虑折半搜索:预处理出左右两边分别的逆序对个数,然后状压求出右边选不同数时和左边形成的逆序对数,然后在左边搜索。
Contest 7
A
一个 (n imes n) 的矩阵里取不在同行同列的 (m) 个数,问这些数和的最大值。
原题的 (m) 非常小,直接枚举即可。
B
求 ([l,r]) 之间,是 (7) 的倍数,不是 (2,3,5) 的倍数的数的个数。容斥。
C
给一张图上的点染色, ([1,a]igcup [b+1,n]) 染成蓝色, ([a+1,b]) 染成红色,请你选择合适的 (a,b) 使得双色边最少。
令 (f_{i,j}) 为 (a=i,b=j) 时的答案,我们考虑每条边的贡献:对于一条边 ((u,v)) ,只有 (i,j) 恰有一个数被包含,这条边才是双色边。也就是说,这条边会对以下部分做出贡献:
于是就转化成了一个扫描线求最小覆盖次数的问题。
D
给出一个序列 ({a_n}) ,一个数 (x) 初始为0,每轮从数列里抽取一个数 (a_i) 并将这个数变为 ((x+a_i)\%n) ,问有多少种玩法,使得 (t) 轮之后 (d|x) 。
(t) 很小的时候可以考虑这样一个 (dp) :设 (f_{i,j}) 表示 (i) 轮之后 (x=j) 的方案数。这时我们发现这个状态有一个性质: (f_{i_1,j_1} imes f_{i_2,j_2}=f_{i_1+i_2,(j_1+j_2)\%n}) 。于是可以直接卷出来答案。
Contest 8
A
给出全集和三个全集子集的元素个数,求恰被两个集合包含的数的最小个数。式子很简单不放了。
B
有 (n) 个任务,第 (i) 个任务需要耗费 (t_i) 的时间并要求在 (d_i) 之前完成,同一时间只能做一个任务。如果要求完成任务的顺序是按照 (d_i) 从小到大排序(相等的取编号小的),请你求每个作业的开始时间使得第一个作业开始时间尽量晚。
从后往前贪心做即可。
C
定义约数链为后一个数是前一个的倍数的数列。请问用不超过 (m) 的数组成的 (n) 个数的约数链共有多少种?
数据小的话可以 (dp) :设 (f_{i,j}) 为前 (i) 个数,最后一个数是 (j) 的答案。转移就直接枚举倍数即可。但是如果 (m) 比较大,就不能直接暴力 (dp) 了。我们把第一位滚掉后枚举一下可以发现当 (gcd(j,k)=1) 时, (f_{j imes k}=f_j imes f_k) ,即 (f) 是一个积性函数。然后对于每个 (p) ,求出 (p^j) 的答案就可以线性筛了。
D
求删去三条边使得图不连通的方案数。
直接求三条边不好求,枚举一条边的复杂度是可以接受的,所以我们只需要求剩下两条边的方案数。图不连通都要记上,所以我们主要来看图连通的情况。既然涉及到了连通,我们就往生成树上想一想,分几种情况讨论。
- 删一条树边,一条非树边:
1.树边不被任何非树边覆盖;
2.树边仅被删去的非树边覆盖。 - 删两条树边:
1.至少一条树边不被任何非树边覆盖;
2.所有覆盖这两条边的非树边都同时覆盖这两条边。
想求出这些,我们需要先知道每条树边被哪些非树边覆盖。可以利用哈希来做,给非树边随机一个权值然后异或(其他有逆运算的也行)。为了方便处理权值,我们可以直接将dfs树(利用其只有返祖边的性质)作为生成树。这样走到的时候记录上,回溯的时候再异或一下(或者其他运算的逆运算)。最后我们将权值排序或者map
一下,就可以求出来权值为0或相同的方案数。
Contest 9
A
给出一个数列,求出两两之间 (gcd) 的最大值、满足此条件的 (i,j) 的个数和满足此条件的 (sum a_ia_j) 。
不能直接枚举两个数,我们就枚举 (gcd) ,然后统计 (gcd) 的倍数。
B
有 (n) 个楼梯,现在在每两个楼梯之间贴上箭头,问有多少种贴法,使得两边箭头都不指向自己的楼梯恰好为 (m) 个。
倍增优化dp。
C
有 (n) 队选手合影,每队3人,要求每队的3人不能全挨在一起,求方案数。
可以容斥做:有一队不满足要求的 (-) 有两队不满足要求的 (+cdots)
D
请你在一棵树上实现:删除某条带权路径、修改某条带权路径的权值和不与某节点相交的路径的最小权值。
首先可以二分答案转化成判定小于等于某个权值的路径交集是否与该节点相交。判断两条路径相交可以分类讨论,然后对两条路径的四个端点交叉求LCA。对于求交,我们可以按照权值排序,然后我们发现每次算的是一个前缀的交,我们就可以预处理出没有修改和删除的答案。在此基础上加一个线段树可以实现删除操作。对于修改操作,我们把它们离线下来,然后在线段树上实现删除和撤销删除。
Contest 10
A
一个长度为 (n) 的仅包含012的字符串,每轮操作对字符串中所有 (ge2) 的数 (-=2) 并将其两侧的数 (+=1) 。求出无法进行操作时的字符串。
首先可以猜证明出操作顺序对答案没有影响,于是可以开始乱搞:我们考虑一个前缀一次执行完所有操作后再对下一个元素执行,发现带来的影响是将最后一个0向后移动,于是可以用栈维护。
B
(m) 个店铺, (n) 种商品,每种商品在一个区间内出售, (m) 个人,每个人会买自己倍数的商店里的商品,求每个人能买到的商品数。
对于一个标号为 (i) 的人,我们发现所有长度 (ge i) 的区间都会取到,只需要处理长度 (<i) 的区间即可。此时相当于一个区间加一,可以用树状数组/线段树维护。
C
(n) 个交易所,在一个交易所可以花费一定权值买一个物品,也可以以此权值卖出。同一时间只能持有一个物品,问最大收益和此条件下最小交易次数。有区间修改操作。
只有查询比较简单,如果加上修改就需要线段树来维护,要加上几个标记。
D
咕