G. Skibidus and Capping
扫描线 数论

合法数对个数,显然扫描线
对于一个质数 p p p那么 l c m ( p , q ) lcm(p,q) lcm(p,q)为半质数,则要求, q q q要么是一个不等于 p p p的质数,这维护前缀质数个数以及每个值的出现次数即可。
要么是一个半质数且是 p p p的倍数,这去枚举 p p p的倍数太慢了,考虑一个数组直接维护每个质数的倍数里半质数的数量。更新就是枚举到一个半质数 v = p q v=pq v=pq时,给 p , q p,q p,q的这个值更新,计算量很小
对于一个半质数 v = p q v=pq v=pq, l c m ( x , v ) lcm(x,v) lcm(x,v)是半质数,那么 x x x可以是 p , q , p q p,q,pq p,q,pq。对于一个半质数 v = p 2 v=p^2 v=p2, x x x可以是 p , p 2 p,p^2 p,p2。这可以通过维护元素出现次数计算。
F. Coprime Subsequences
因子反演 子序列计数

子序列实际上这里就可以看成子集。可以不管原始的顺序,转化到值域上做。
g c d gcd gcd恰等于某个值不好算,可以计算 g c d gcd gcd是 x x x的倍数的答案 g ( x ) g(x) g(x)。枚举 x x x,计算出 x x x的所有倍数的个数,可以从这些倍数里任选元素组成非空集合,个数就是 2 c n t − 1 2^{cnt}-1 2cnt−1。
然后用 g ( x ) g(x) g(x)计算 g c d = x gcd=x gcd=x的答案 f ( x ) f(x) f(x),可以枚举 x x x的所有倍数(不包含 x x x),从 g ( x ) g(x) g(x)里减去这些 f ( k x ) f(kx) f(kx),剩下的就是 f ( x ) f(x) f(x)了。这要求计算 f ( x ) f(x) f(x)时 f ( k x ) f(kx) f(kx)都算好了,需要从大到小递推。
当然这和莫比乌斯反演也是等价的,但是本题复杂度支持我们直接调和级数枚举的递推,这样就可以了。
D. Board Game
树套set 优化最短路

到了一个点 x , y x,y x,y之后,可以通过所有 a < = x , b < = y a<=x,b<=y a<=x,b<=y的点,到 c , d c,d c,d。问最少用多少次操作,这相当于边权全是 1 1 1的图的最短路。
每个点都和 a < = x , b < = y a<=x,b<=y a<=x,b<=y的所有点有连边,这样边太多,不能直接跑最短路。注意到这是边权全都相同,可以转化成 b f s bfs bfs,每个点只有第一次到达才是最短距离,后面不会更新。所以每个点只应该入队一次,这样复杂度就有保证了。
那么问题是如何实现这一点?一个经典 t r i c k trick trick是,用数据结构在开始保存所有点,然后每次要入队时,从数据结构种取出 a < = x , b < = y a<=x,b<=y a<=x,b<=y的所有点,入队。这样每个点被取出之后就没了,只能被入队一次就实现了。
这里的难点是,每次是一个二维查询,并且我们是最短路,相当于在线查询,不能离线,需要一个支持在线二维查询的数据结构。考虑树套树,一个维度用树状数组/线段树,一个维度,我们只要每次能取出 b < = y b<=y b<=y的所有元素即可, s e t set set就可以。
树套树复杂度是 O ( n log 2 n ) O(n\log ^2 n) O(nlog2n)