POI2013 MOR-Tales of seafaring
给 n n n 个点 m m m 条边无向图,边权均为 1 1 1,每次询问两个点之间是否有长度为 d d d 的路径,可以不是简单路径。
因为你可重复经过一个点,所以你可以让一个距离无限加 2 2 2 也就是在不改变奇偶性的前提下无限增大。这样我们跑最短路,对于每个点我们接纳第一个偶数最短路和奇数最短路,预处理任意两点这样的两个不同奇偶性的最短路径。询问的时候,看看与它奇偶性相同的最短路径长度是不是比它短即可。
Problem 22
- 现在我们要选出一些不相交的线段,让它们的价值最高。我们把右端点相等的操作放在一起,那么设 f i f_i fi 是种了右端点为 i i i 的地能获得的最大价值,枚举一下以 i i i 为右端点的,这些东西我们只能选一个。那么转移为
f i = max 1 ≤ i ≤ k ( s r i − s l i − 1 + p i + max 1 < i f i ) f_i = \max_{1 \leq i \leq k} (s_{r_i} -s_{l_i-1} + p_i +\max_{1 <i} f_i) fi=1≤i≤kmax(sri−sli−1+pi+1<imaxfi)
外面的 max \max max 暴力一下,里面的 max \max max 维护一下前缀最大值。
- 这意味着一块地你开垦一次就可以了,那么 dp 也不知道哪些土地被开垦了。那么先随便限制一个东西大小,就按左端点从小到大排序,状态还是 f i f_i fi 是种的最靠右的土地为 i i i 的最大价值,那么枚举一下转移,也不知道转移哪个点是吧那就讨论一下,假设要转移到 f j f_j fj,也就不包含、部分包含、完全包含三个情况。因为你限制了左端点,所以你只要看看 j j j 与 l i l_i li 和 r i r_i ri 之间的关系,它可能转移到 j j j,也可能在 j < i j<i j<i 时转移到 i i i,所以用一棵区间加和区间取 min 值的线段树即可。
魔术师
考虑前缀和,区间
[
l
,
r
]
[l,r]
[l,r] 总数的奇偶性相当于问你
s
l
−
1
s_{l-1}
sl−1 和
s
r
s_r
sr 的奇偶性是否相同,那么可以在
l
l
l 和
r
r
r 之间连一条边,如果一个联通块中有一个点我们知道了,那么就全知道了。现在确定了
s
u
m
0
=
0
sum_0 = 0
sum0=0,那么我们求一个将全部点连起来最小生成树即可秒啊。
运输计划
有带边权的树,有 k k k 条路径,告诉你它们的起点终点,求允许把一条边边权改为 0 0 0,最小化最长的路径的长度。
先二分,问题转换成了把一条边改成 0 0 0 的前提下能否所有路径的长 < m i d <mid <mid,然后你找出不合法的路径,用树上差分和求它们的交删掉边权最大的边再看看合不合法。
Problem 20
这个东西随便做吧,只不过方案数不好求,那么我们按每个人按能力排序,当你转移到不得不选队长时再选,这样不会算重了。
BZOJ 3306
给你一棵大小为 n n n 的有根有点权树支持换根、修改点权、查询子树最小值。
拓扑排序
- 求字典序最小的拓扑序
与顺序无关,优先队列
- 从 DAG 上一个点出发的路径条数
按照倒着的拓扑序进行 dp
- 求拓扑图上 S → T S \to T S→T 的必经边
先求出 S S S 到每个点的路径条数 f f f 和每个点到 T T T 的路径条数 g g g。如果一条边 ( x , y ) (x,y) (x,y) 满足 f x × g y = f t f_x \times g_y = f_t fx×gy=ft 那么是必经。
- 秒啊
跑一下 DAG 最短路,容易求可以在 S 1 → T 1 S_1 \to T_1 S1→T1 的最短路上的边和在 S 2 → T 2 S_2 \to T_2 S2→T2 最短路上的边,那么这些边的交集构成了最多两个拓扑图,求一下 DAG 最长路即可。
贪心乱搞
求有向图尽量长的简单路径,可以不是最长,保证存在哈密顿回路。
1 ≤ n ≤ 1 0 5 1 \leq n\leq 10^5 1≤n≤105。
Bubble Cup 13 - Finals [Online Mirror, unrated, Div. 2]
写了 G 和 J 两道大水题,还把 M 丢给 ljh 大佬了,菜死了。
- G Years
下标较大的区间覆盖问题,对区间离散化在差分覆盖,并记录对应回去的编号
int n = read();
for (int i = 1; i <= n; i++) {
a[i].l = read(), a[i].r = read(); a[i].r--;
d[++cnt] = a[i].l, d[++cnt] = a[i].r+1;
}
sort(d + 1, d + cnt + 1);
int num = 0;
for (int i = 1; i <= cnt; i++) {
if (d[i] == d[i - 1]) continue;
mp[d[i]] = ++num, rev[num] = d[i];
}
- J Lonely Numbers
给你 n n n 个数 1 ∼ n 1\sim n 1∼n,求有多少个数是孤独的。一个 a a a 是孤独的当且仅当不存在 b ∈ [ 1 , n ] b \in [1,n] b∈[1,n] 使得 gcd ( a , b ) , a gcd ( a , b ) , b gcd ( a , b ) \gcd(a, b), \frac{a}{\gcd(a, b)}, \frac{b}{\gcd(a, b)} gcd(a,b),gcd(a,b)a,gcd(a,b)b 能构成三角形。
假设 a < b a< b a<b
-
a ∣ b a|b\quad a∣b 三条边为 1 , a , b a 1,a,\frac{b}{a} 1,a,ab 易知 1 ≤ a 1 \leq a 1≤a
- a = b a a = \frac{b}{a} a=ab 即 a 2 = b a^2=b a2=b 满足 1 + a > a 1 +a > a 1+a>a
- a ≠ b a a \not= \frac{b}{a} a=ab 显然 ∣ a − b a ∣ ≥ 1 |a - \frac{b}{a}| \ge 1 ∣a−ab∣≥1 不满足
-
gcd ( a , b ) = 1 \gcd(a,b) = 1\quad gcd(a,b)=1三条边为 1 , a , b 1,a,b 1,a,b 而 a ≠ b a \not= b a=b 所以不可能构成三角形。
-
gcd ( a , b ) ≠ 1 \gcd(a,b) \not= 1 gcd(a,b)=1 且 a ∤ b a \not| b\quad a∣b 即为 a , b ∉ P a,b \notin \mathbb{P}\quad a,b∈/P 令 d = gcd ( a , b ) d=\gcd(a,b) d=gcd(a,b) 易知 a d < b d \frac{a}{d} <\frac{b}{d} da<db
- d + b d − a d = d + b − a d ≥ 2 b − a > 0 d+\frac{b}{d}-\frac{a}{d}=d+\frac{b-a}{d} \ge2\sqrt{b-a}>0 d+db−da=d+db−a≥2b−a>0
- b d + a d − d = a + b − d 2 d \frac{b}{d}+\frac{a}{d}-d=\frac{a+b-d^2}{d} db+da−d=da+b−d2 有 d ≤ a d\leq \sqrt{a} d≤a 所以 a + b − 2 × a d > 0 \frac{a+b-2 \times a}{d} > 0 da+b−2×a>0
综上,答案为 f ( n ) − f ( ⌊ n ⌋ ) + 1 f(n) - f(\lfloor \sqrt{n} \rfloor )+1 f(n)−f(⌊n⌋)+1。其中 f n f_{n} fn 为 [ 1 , n ] [1,n] [1,n] 内质数的个数。线性筛一下就可以 O ( 1 ) O(1) O(1) 回答询问了。
- M Ancient Language
CF510C Fox And Names 这个题和 M 差不多吧,就是拓扑排序一下子了,复杂度瓶颈在于输入,卡常差评。
CF1239B The World Is Just a Programming Task
给你一个括号组成的序列(不一定是合法的括号序列)。
你要任意交换 2 2 2 个位置,使得得到的序列有尽量多的循环移位,使得移位后序列是合法的括号序列。
我们先循环移位让它变成一个合法括号序列,因为两次循环移位可以通过一次循环移位搞定。还是老套路,建个折线图把左括号看成上升右括号看成下降。
如果我们交换了两个括号呢,假设它构成了一个低谷,那么交换了还不如不交换的,那么我们交换一定想让它多几个低谷。而一次交换要让一段的纵坐标向下平移一个单位,那么我们找到一个左括号一个右括号交换一下,使得中间出现的低谷尽可能多,也就是中间的
2
2
2 尽可能多。
CF1120F Secret Letters
这个性质神仙啊,你考虑在正确答案中某一位你寄存了,你啥时候让令一个人取走了,假设你在
t
t
t 的时间让它取走了,那么你之间还不如交替取,也就是你帮我我帮他去取,这样最多也在
t
t
t 取走,那就枚举从哪个地方开始就行了。
二分经典题
- 求序列第 k 大和子序列 / 子段
dp 乱入,因为序列的顺序是没关系的,所以排个序,搞个状态 f i , j f_{i,j} fi,j 表示前 i i i 个数和为 j j j 然后转移上 k k k 次,转移次数很少的话可以存有用状态。子段的话,直接暴力 dp 或求出所有的子段冲。
- 求字符串第 k k k 小字典序的子串
优先队列乱入,虽然好多人写的 SAM。这个你就将一个个字符插进去,每次取出字典序最小的,加上在它后面的字符做 k k k 次就行。
- 求字符串第 k k k 小字典序的子串
SAM 乱入,TJOI2015 弦论直接冲。
n ≤ 1000 n \leq 1000 n≤1000 拿出所有的子串排个序,二分一下答案用 dp check。设 f i , j f_{i,j} fi,j 表示前 i i i 个划分成了 j j j 段,然后接下来新划分的串要大于你的二分那个串。
- 区间 gcd 和
线段树或 ST 表维护区间 gcd,每个点为右端点,二分向左找有多少段不同的 gcd,我们知道长 n n n 的序列最多有 log n \log n logn 个不同的 gcd,所以带两个 log \log log。
经典题
给定序列 a a a,每次操作 ( a i − 1 , a i , a i + 1 ) → ( a i − 1 + a i , − a i , a i + 1 + a i ) (a_{i-1},a_i,a_{i+1}) \to (a_{i-1}+a_i,-a_i,a_{i+1}+a_i) (ai−1,ai,ai+1)→(ai−1+ai,−ai,ai+1+ai),求序列 a a a 能否到序列 b b b。
前缀和一下
x y z
x + y -y z + y
x x + y x + y + z
x + y x x + y + z
屑题。