zoukankan      html  css  js  c++  java
  • 好题题集1

    毒瘤思维题汇总1

    毒瘤思维题汇总2

    Intrinsic Interval

    对于一排列 (p_i),定义“好区间”为值域连续的一段区间。

    现给定一长为 (n) 的排列 (p_i)(q) 组询问,求包含区间 (l...r) 的最短好区间是哪个。

    (1 le n,q le 10^5)

    首先考虑求问题的弱化版:求一个排列的所有好区间。即经典题 Pudding Monsters

    对于一个排列来说,一段区间为好区间当且仅当 (r - l = mx - mn),其中 (mn,mx) 分别为区间最小值最大值。并且更重要的是,(mx-mn ge r - l),于是我们只需要维护 (mx-mn) 的最小值,判断其是否为 (r-l) 即可。

    具体实现类似 异或凑数那题,考虑移动右端点对所有左端点的影响。用线段树维护 (mx-mn+l) 的最小值及出现次数,用单调栈来维护 (mx,m) 即可。

    回到原问题。一个比较显然的事实是:如果 ([l,r],[s,t]) 均为好区间,且 (l le s le r le t),那么 ([s,t]) 也是好区间。因此包含 (l...r) 的最短好区间只有一个。我们只需要找到最先覆盖 (l...r) 的那个区间即可。

    将询问挂在右端点上,扫到时取出。维护取出的询问的大根堆,以 (l) 为关键字。线段树上二分判断是否有解。有解下一个,无解直接退出。

    复杂度:(O(n log n))

    共价爷想构造一棵 $ N $ 个点的有根树,其中 $ 1 $ 号点是根。
    显然的,对于一棵有根树,我们可以定义每个点的深度为,这个点到根的路径上点的个数(包括端点),也就是说,$ 1 $ 号点深度为 $ 1 $。
    共价爷希望,深度为奇数的点的个数,刚好为 $ K $ 个。
    他想知道有多少棵不同的满足条件的有根树,你只需要输出答案对 $ P $ 取模的结果。

    我们认为两棵树不同,当且仅当存在一对点 $ (i, j) $,满足 $ i $ 和 $ j $ 在一棵树中有边相连,而在另一棵树中没有边相连。

    对于 $ 100% $ 的数据,$ 1 < K < N (,) N leq 500000 $,当 $ N > 1000 $ 时,$ P $ 均为 $ 998244353 $。

    看到奇偶要想一想二分图啊!!

    树计数还是基尔霍夫矩阵树定理和prufer序列好使

    考虑将奇数层的点分为左部图,偶数层的点分为右部图,分配完标号后,我们要解决的问题为:左部点为 (1...n),右部图为 (n + 1...n + m) 的带标号完全二分图的无根树生成树数量。即经典题 文艺计算姬

    可以用基尔霍夫矩阵树定理大力推导,也可以用prufer序列得出。

    prufer序列:

    考虑左部图的点的总度数和为 (n + m - 1),右部点的总度数和也为 (n + m - 1),那么它们在 prufer 序列上的出现次数分别为 (n + m - 1 - n = m - 1)(n + m - 1 - m = n - 1)

    注意到,当我们确定好左部图的点在 prufer 序列的相对位置,以及右部图的点在 prufer 序列的相对位置时,根据prufer转无根树以及二分图性质(边两端点一左一右)可知,唯一对应了一种无根树。于是构成了映射关系。答案为 (n^{m-1} imes m^{n-1})

    所以原题的答案为 ({n - 1 choose k - 1} imes k^{n-k-1} imes (n-k)^{k-1})

    复杂度:(O(n) + O(log n))

    人类智慧之神 zhangzj 最近有点胖,所以要减肥,他买了 $ N $ 种减肥药,发现每种减肥药使用了若干种药材,总共正好有 $ N $ 种不同的药材。

    经过他的人脑实验,他发现如果他吃下去了 $ K(0 leq K leq N )$种减肥药,而这 $ K $ 种减肥药使用的药材并集大小也为 $ K $,这 $ K $ 种才会有效果,否则无效。
    第 $ i $ 种减肥药在产生效果的时候会使 zhangzj 的体重增加 $ P_i $ 斤,显然 $ P_i $ 可以小于 $ 0 $。

    他想知道,一次吃药最好情况下体重变化量是多少,当然可以一种药也不吃,此时体重不变。
    由于某些奥妙重重的情况,我们可以让这 $ N $ 种减肥药每一种对应一个其使用的药材,且 $ N $ 种减肥药对应的药材互不相同(即有完美匹配)。

    对于 $ 100% $ 的数据,$ 1 leq N leq 300, |P_i| leq 1000000 $。

    根据霍尔定理,如果二分图有完美匹配的话,左部图任选一集合,其对应的右部图集合不小于左部图的哪个集合。

    考虑最大权闭合子图。但是只能保证右部图集合大于等于左部图集合。于是先跑一遍匹配求出方案,右向左连边,再跑一遍最大权闭合子图,这样就能保证左部图集合大于等于右部图集合了,此时左部图集合显然等于右部图集合。

    显然得到的解均为合法解,并且可以证明合法解均可能被得到。

    排序

    给定一长为 (n) 的排列,以及 (m) 次操作。每次操作为将一个区间内的元素按升序或降序排序。问最后第 (k) 项的值。

    (1 le n,m le 100000)

    每次局部排序不太好维护(可能能用 ODT 维护?)

    但是考虑到字符集只有 (w) 的序列可以通过 (w) 棵线段树实现单次排序 (O(w log n))。具体见A Simple Task。维护一下小于/大于当前字符的字符的个数,区间覆盖即可。

    既然这道题最后只问第 (k) 项,我们可以二分答案 (t),通过最终 (< t) 的数的个数来判断((t) 偏大时 (<t) 的数的个数不减)。这样,我们就只用对序列进行排序了,复杂度为 (O(n log n))

    方格染色

    (n imes m) 的网格,每个格子可以涂 R 或者 B。要求每个 (2 imes 2) 的格子中 RB 的出现次数均为奇数。

    现已知 (k) 个格子的颜色,求在此前提下所有合法方案数。

    (1 le n,m,k le 10^5)

    其实是一类问题了。和 Appleman and Complicated Task 类似。这提示我们网格图除了想二分图,对偶图,插头DP以外,还可以想一想找规律(尤其是网格图染色计数)。

    通常的规律是:确定一行/一列/一行一列/一个点以后整个网格图的方案就都确定了。当然有的题也可能是用较为可做的方法搞定 ((n-1) imes (m -1)) 后剩下一行一列有且仅有一种方案使得整个网格图调整到合法,如 普及组

    此题将 R 看作 1,将 B 看作 0 以后,限制为 (2 imes 2) 的格子的异或和均为1.

    然后开始找规律。发现确定好一行一列后整个网格图就确定了。并且 ((x,y)) 的值为 (c(1,1) oplus c(x,1) oplus c(1,x) oplus ([x mod 2 = 0] cdot [y mod 2 = 0]))。枚举好 (c(1,1)) 后,问题转化为:(x = 0,x = 1,x oplus y = 0, x oplus y = 1) 四种操作。其中前两种操作可以转化为 (x oplus c(1,1) = v)。的操作。于是高斯消元边带权并查集搞搞就好了。

    复杂度:(O(n log n))

    Euclid's nightmare

    给定 (n)(m) 维向量,每个向量只有 (1) 维或 (2) 维为 (1),其余为 (0)。规定向量的加减法对 (2) 取模。

    问:

    • 线性基大小
    • 字典序最小的那种线性基的编号集合
    • 最大异或和

    (1 le n,m le 5 cdot 10^5)

    考虑模拟线性基。

    只有一维为 (1) 的情况好说,判一下这一维有没有基向量,如果没有就插入。

    如果有两维为 (1),假设 (a)(b)(1)。那么我们找到用当前已经插入的基向量能把 (a)(b) 分别异或到哪里去。此处的“异或到”表示通过异或基向量,使得由 (x)(1) 转化为 (y)(1),且 (y) 这一维没有基向量。假设 (a) 被异或到了 (c)(b) 被异或到了 (d),那么我们就插入到 (c),并向 (d) 连一条边,表示其余向量如果 (c)(1) 的话,可以被异或到 (d) 去。但是,有可能 (a) 异或着就变成 (0) 了(遇到了只有一维为 (1) 的基向量),那么说明 (a) 这个 (1) 可以被线性表出,我们就不用管它了,问题简化为只有一维为 (1) 的情况。

    如果一直暴力走边,可能会变成 (O(nm))。发现可以用类似并查集路径压缩的方法来解决这个问题。复杂度变为 (O(n log m))

    线性基大小好说。字典序最小也好说,当前能插就插即可。

    最大异或和也还好,因为我们可以保证基向量除掉“当前维”(指这个基向量被插到了哪一维)以外的那个“附带维”一定小于“当前维“,或者没有”附带维“,这样的话就和普通线性基完全一样了。对”当前维“排序,贪心异或即可。

    复杂度:(O(n log m))

    语言

    给定一棵 (n) 个点的树。给定 (m) 条链 ((s_i,t_i))

    对于每个点,求出其仅通过一条链能到达的点的数量。

    (1 le n,m le 10^5)

    考虑只问一个点 (p) 怎么做。此时仅需考虑过 (p) 的链。可以发现,答案为所有过 (p) 的链的 (s,t) 组成的点集的虚树的大小,可以用寻宝游戏的方法做。即 (sum_u dep(u) - sum_{u,v}[u,v为dfn上相邻的点]dep(lca(u,v))),其中第一个和最后一个也算相邻。

    考虑用线段树维护虚树大小。对 (dfn) 建线段树,节点存仅考虑节点内的 (dep) 以及相邻点 (dep(lca)) 的贡献的答案。pushup 的时候顺便维护一下 (dep(lca)),最终记得把 第一个和最后一个的 (dep(lca)) 也减掉。

    那么这道题基本上就算做完了。至于“只考虑过 (p) 的链”的限制,可以通过树上差分搞定。

    复杂度:(O(n log^2 n)),可以做到 (O(n log n))

    Triple

    (n) 个集合幂级数,每个集合幂级数只有三个位置有值,第 (i) 个集合幂级数 (F_i)(F_i(a_i) = x, F_i(b_i) = y, F_i(c_i) = z)。其中 (x,y,z) 为常量,所有集合幂级数的 (x,y,z) 都一样。

    现求将这 (n) 个集合幂级数做异或卷积以后的每一位的值。

    (1 le n le 2 cdot 10^5,0 le a_i,b_i,c_i < 2^k,1 le k le 17,0 le x,y,z le 10^9)

    首先有一个暴力 FWT 的做法,复杂度为 (O(nk2^k)),还不如暴力 DP。我们考虑优化。

    我们不用每次都 IFWT,直接所有的做 FWT 最后乘完一起卷回来即可。复杂度仍为 (O(nk2^k))

    发现复杂度瓶颈在 FWT 上。因为一个集合幂级数只有三个位置有值,我们可以直接根据 FWT 的公式:(hat{f}(S) = sum_T (-1)^{|S cap T|}f(T)),可以做到单次 (O(n)) 的 FWT。复杂度成功优化到了 (O((n+k)2^k))终于和暴力 DP 一样了

    考虑实质性的优化。发现我们最后要求的主要是这个东西:

    [egin{aligned} hat{f}(S) &= prod_{i=1}^n sum_T (-1)^{|S cap T|}f(T)\ &= prod_{i=1}^n (-1)^{|S cap a_i|} x + (-1)^{|S cap b_i|}y + (-1)^{|S cap c_i|}z\ end{aligned} ]

    发现 (x,y,z) 的系数组合只有八种可能,如果我们知道了这八种组合中每个组合的出现次数,就可以直接快速幂搞定了。

    然而八种还是太多了,这里有一种简化的操作:每个三元组先强制选上 (a_i),然后再从 (0,a_i oplus b_i,a_i oplus c_i) 三种选择中选一种,最后输出答案的时候下标异或上 (igoplus_i a_i) 即可。这样,我们就将 (a_i,b_i,c_i) 转化为了 (0,a_i oplus b_i,a_i oplus c_i),第一项的系数一定为 (1)。八种组合简化为了四种组合。设

    [c_1 = count(x+y+z)\ c_2 = count(x+y-z)\ c_3 = count(x-y+z)\ c_4 = count(x-y-z) ]

    并且我们知道 (c_1 + c_2 + c_3 + c_4 = n),只要再知道三个方程就可以解出来了。

    接下来的操作比较神奇:

    看着 (prod) 感觉很不爽,因为我们想要的是 (sum)。如果我们知道 (sum_i (-1)^{|S cap b_i|}y),或者哪怕是 (sum_i (-1)^{|S cap b_i|}),我们就能再搞出个方程:(c_1+c_2-c_3-c_4 = ...) 了。

    看到 ((-1)^{|S cap b_i|}),不难想到 FWT,或许我们可以找到某个集合幂级数,使得其 FWT 的结果是这个东西。构造一个集合幂级数 (g),其中 (g(S) = sum_i [b_i = S])。考虑 (hat{g}(S)) 是什么东西:

    [egin{aligned} hat{g}(S) &= sum_T (-1)^{|S cap T|} sum_i [b_i=S]\ &= sum_i sum_T [b_i = S] (-1)^{|S cap T|} \ &= sum_i (-1)^{|S cap b_i|} end{aligned} ]

    正是我们想要的。同理,对于任意的 (f(i)),我们设 (g(S) = sum_i[f(i) = S]),都有 (hat{g}(S) = sum_i (-1)^{|S cap f(i)|})。那么我们就可以令 (f(i) = c_i),就有了 (c_1 - c_2 + c_3 - c_4 = ...) 了就剩最后一个了。

    我们打算在 (sum_i (-1)^{|S cap b_i|} imes (-1)^{|S cap c_i|}) 上下手。因为这个东西等于 (sum_i (-1)^{|S cap (b_i oplus c_i)|}),于是我们令 (f(i) = b_i oplus c_i) 就可以得到 (c_1 - c_2 - c_3 + c_4 = ...)

    总结一下:

    [c_1 + c_2 + c_3 +c_4 = A\ c_1 + c_2 - c_3 - c_4 = B\ c_1 - c_2 + c_3 - c_4 = C\ c_1 - c_2 - c_3 + c_4 = D ]

    其中 (A,B,C,D) 都是可以求出的东西。那么我们就可以手动解方程得到 (c_1,c_2,c_3,c_4) 了。快速幂后 FWT 回去即可。

    复杂度:(O((k + log n)2^k))

    双倍经验:黎明前的巧克力

    节日庆典

    给定一长为 (n) 的字符串 (s)。对于每个前缀 (1...i),求出其循环移位的最小表示的开头(多解输出最前面)。

    例如 abaacaba 的答案是 1 1 3 3 3 6 3 8

    (n le 3 cdot 10^6)

    首先有一些 (O(n^2)) 的做法,比如俩指针的线性做法,以及 Lyndon 分解,不过对正解用处不大。

    还有一个 (O(n^2)) 的做法:每个前缀只有最小的后缀,以及带着最小后缀作为前缀的那些后缀,有可能成为答案。维护一下这些就好了。比较求解的话可能需要一个 (O(1)) 求后缀与整个串的 LCP 的算法,可以 exKMP 预处理。

    然而,这些不一定全部有用。一种比较显然的情况是有两个候选后缀 (s,t),其中 (lcp(s,t) < min(|s|,|t|)),这时候已经能够知道它们的大小关系了,就可以把大的那个直接扔掉了,以后也不会用到了。然而复杂度仍然是 (O(n^2)),一个 aaaaaaaaa 就全卡满了。

    还有一个特别妙的优化:如果两个后缀 (s,t),满足 (|s| < |t| < 2|s|),那么较短的那个串 (|s|) 不可能成为候选后缀。证明:

    如果 (|s| < |t|< 2|s|),那么 (t-s) 是一个循环节。那么 (s=uv,t=uuv)(s) 是候选后缀,至少要求存在一个串 (w),使得 (s) 接上 (w)(t) 接上 (w) 要小。即:(uvw < uuvw),即 (vw < uvw),即 (vw < sw),而 (v) 是一个后缀,那么至少 (v) 就可以代替 (s) 成为最小后缀了。所以 (s) 不可能成为候选后缀。

    这样,候选后缀就只有 (O(log n)) 个了。总复杂度为 (O(n log n)),可以通过此题。

    Mr. Kitayuta's Gift

    给定一个长为 (m) 的小写字母串 (s) 和一个正整数 (n)

    (s) 是多少个长为 (n) 的回文串 (t) 的子序列。

    (m le 200,n le 10^9)

    考虑DP。设 (f(i,l,r)) 表示回文串已经确定好了左边 (i) 个和右边 (i) 个,且尽可能匹配 (s) ,使得 (s) 剩下 (l...r) 的方案数。设 (g(i)) 表示回文串已经确定好了左边 (i) 个和右边 (i) 个,且匹配好了 (s) 的方案数。

    (s_l = s_r) 时:

    [f(i,l,r) o f(i+1,l+1,r-1)\ f(i,l,r) o 25f(i+1,l,r) ]

    (s_l ot= s_r) 时:

    [f(i,l,r) o f(i+1,l,r-1)\ f(i,l,r) o f(i+1,l+1,r)\ f(i,l,r) o 24f(i+1,l,r) ]

    (g) 的转移是 (g(i) o 26g(i+1))

    (r-l le 1)(s_l = s_r) 时有 (f(i,l,r) o g(i + 1))

    最终答案为 (g(lceil frac{n}{2} ceil))

    然后就可以 (O(m^2n)) 地转移了。

    但是 (n) 很大,于是考虑矩阵快速幂,复杂度为 (O(m^6 log n))

    考虑开拓新思路。不易发现,我们的转移可以看作在一个自动机上跑,(i+1) 相当于跑一步。自动机上共有三种点,分别时 (s_l=s_r) 的“绿点”,(s_l ot= s_r) 的“红点”,以及 (g)(终点),图见xht博客。每一条从起始状态到终点的恰好跑了 (lceil frac{n}2 ceil) 步的路径唯一对应着一种合法转移方案。

    不难发现我们的转移的方案数的计算至于路径上的红绿点个数有关。如果我们能对每一种 (i) 个红点 (j) 个绿点的路径都算出来方案数的话,就不难得到答案了。不难发现 (j=lceil frac{m-i}{2} ceil),于是路径数只有 (O(m)) 种。至于到底有多少条 (i) 个红点 (j) 个绿点的路径,可以DP解决。设 (f(i,l,r)) 表示从 (l...r) 状态开始继续往下跑,接下来(含自己)将会有 (i) 个绿点的路径条数。这个可以 (O(m^3)) 计算。

    抽出 (O(m)) 种链后,我们得到了一个 (O(m^4 log n)) 的方法。

    考虑继续优化。发现这 (O(m)) 种链可以长得很像,于是可以直接放在一张自动机上一次跑完。图见xht博客,每种链的方案数体现在红点指向绿点的边上。(比较特殊的是,由于可能有的方案没有经过红点,我们的初始状态为第一个红点有一种方案,第一个绿点有 (f(0,1,m)) 种方案)

    复杂度:(O(m^3 log n))

    常数优化:矩阵张的是半个三角,怎么矩乘也是半个三角,于是只用算 (i le k,k le j) 的情况。常数可以除以 (6)

    机场 / Airport

    飞机场有 (a+b) 个停机位,其中 (a) 个停机位有登机桥连接飞机和候机厅,乘客可以通过登机桥直接由候机厅登上飞机;另外 (b) 个停机位没有登机桥和候机厅相连,所以乘客登机需要先搭乘摆渡车再登机。

    毫无疑问,搭乘摆渡车的体验是非常差的,所以每位搭乘摆渡车的乘客都会产生不愉快度。

    现在,给定每架飞机的乘客数量,登机时间和起飞时间;飞机需要在登机时间点选择一个空闲的停机位,在这个时间点内所有乘客会完成登机,然后飞机会一直停在该停机位,直到起飞时间;

    若某飞机在时刻 (x) 起飞,则在时刻 (x) 该飞机所在的停机位是空闲的。

    飞机场的管理层希望能够尽量减少乘客的不愉快度,为此飞机在登机时间到起飞时间之间,可以切换停机位;切换也会产生不愉快度,如果该飞机有 (x) 位乘客,那么切换所产生的不愉快度为 (lfloor p cdot x floor)

    假设某飞机从 (x) 时间开始由停机位 A 切换到停机位 B,那么停机位 A 在 (x+1) 时间是空闲的。能进行这样的切换当且仅当停机位 B 在 (x+1) 时间是空闲的。

    (1 le a,n le 200,b=10^9,0 < p < 1),保证有解

    这是个常见的网络流模型,建议记住,可以用于应对“占用...”的问题。

    将“时间点”看作边,建费用流:

    将时间拉成一串,对每个时间点建一条边,边的容量为 (a),表示每个时间点的“登机桥”最多有 (a) 架飞机。

    对于每个飞机,有三种选择:

    1. 不占用“登机桥“,花费为 (x)
    2. 一直占用”登机桥“,花费为 (0)
    3. (s) 时刻占用”登机桥“,然后迅速切换走,花费为 (px)

    占用”登机桥“可以体现为消耗流量,从主链上分走 (1) 的流量。

    统一减去 (x) 的花费后,如下图:

    airport

    跑最小费用可行流即可。

    Do you like query problems?

    (n) 个数 (a_i),初始为 (0)(Q) 次操作,共三种操作:

    • 1 l r v : 对于区间 (l...r)(a_i = min(a_i,v))
    • 2 l r v : 对于区间 (l...r)(a_i = max(a_i,v))
    • 3 l r v : 对于区间 (l...r),将 (a_i) 累加到答案 (ans) 中。

    (0 le v < m),求所有 ((frac{n(n+1)}{2}(2m+1))^Q) 种可能的操作的答案的和模 (998244353)

    (1 le n,m,Q le 2 cdot 10^5)

    考虑求所有可能的操作的答案的期望。

    分拆贡献至第 (i) 个数第 (j) 次对答案的贡献。第 (i) 个数第 (j) 次有贡献,必须要第 (j) 次为询问且包含 (i)。然后考虑贡献的期望即可。即:

    [E(sum_{i,j} ans) = sum_{i,j} E(ans) = sum_{i,j}frac{i(n-i+1)}{frac{n(n + 1)}{2}} cdot frac{1}{2m+1}E(a_{i,j}) ]

    考虑求 (E(a_{i,j}))。根据套路,(E(a_{i,j}) = sum_{k=0}^{m-1}P(a_{i,j} > k))。因为只有区间取 (min) 和区间取 (max) 操作,(a_{i,j}) 的值只与前 (j-1) 次操作中最后一次作用到它且改变了它的操作。我们规定“改变”指 (min) 操作中 (v < a_{i})(max) 操作中 (v ge a_i)(其它的规定其实也是可以的),那么一次操作作用到它且改变它的值的概率为 (frac{i(n-i+1)}{frac{n(n+1)}{2}} cdotfrac{m}{2m+1}),设其为 (p)。那么 (P(a_{i,j} > k)) 为在 之前曾经有过作用到它且改变它的值的操作 且最后一次这种操作的 (v>k)

    [E(a_{i,j}) = sum_k P(a_{i,j}> k) = sum_k (1-(1-p)^{j-1}) cdot frac{m-1-k}{m} ]

    最后化简一下就好了。

    复杂度:(O(n log n))

    Simple Math 3

    给定四个整数 (A,B,C,D),求所有满足以下条件的 (i) 的个数:

    • ((A+B cdot i)...(A+C cdot i)) 中不含 (D) 的倍数。

    (T le 10^4,2 le D le 10^8, 0 le B < C < D,1 le A < D)

    不难发现,(i) 的上界为 (lfloor frac{D-1}{C-B} floor),再大的 (i) 必然导致 ((A+B cdot i) ... (A + C cdot i)) 中含有 (D) 的倍数。

    注意到 (i le lfloor frac{D-1}{C-B} floor) 的时候,((A + B cdot i) ... (A + C cdot i)) 最多只包含 (1)(D) 的倍数。

    那么可以考虑容斥,计算 ((A + B cdot i) ... (A + C cdot i)) 中含有 (D) 的倍数的 (i) 的个数,就相当于计算 ((A + B cdot i)...(A + C cdot i))(D) 的倍数的个数。即:

    [sum_{i} lfloor frac{A + C cdot i}{D} floor - lfloor frac{A + B cdot i - 1}{D} floor ]

    扩欧计算即可。

    复杂度:(O(Tlog D))

    Stranger Trees

    给定一棵 (n) 个点的无权无向树,对于每个 (0 le k < n),求出这 (n) 个点的所有生成树中恰好与这棵树有 (k) 条边重合的方案数。

    (1 le n le 100)

    经典老题了。

    又是生成树计数,考虑 prufer 序列或者基尔霍夫矩阵树定理。

    根据套路,将这棵树上的边的边权设为 (x),其余设为 (1),然后根据基尔霍夫矩阵树定理得出的所有生成树边权积的和,其中的 (i) 次项为有 (i) 条边重合的方案数。

    然而这样做非常麻烦。考虑到这个多项式只有 (n) 项,我们可以计算 (n) 个点值,然后插值得到答案多项式。

    复杂度:(O(n^4))

    calc加强版

    一个序列 (a_i) 是合法的,当且仅当:长度为 (n) ,值域为 ([1,K]) 且互不相同。

    一个合法序列的权值定义为 (prod_{i = 1}^n a_i)

    给定 (m,K),对于所有的 (n le m) 求所有合法序列的权值和。

    (1 le m le 5 cdot 10^5, 1 le K le 10^9,tl=3s)

    对每个值单独考虑,最后拼接。因为拼接的时候需要分配位置,所以应该使用 EGF。考虑每个值的 EGF 为 (1+kx),那么答案应该是 (frac1{n!}[x^n]prod_{k=1}^K (1+kx))

    但是 (K) 太大了,我们无法用分治 FFT 计算。

    我们猜想把 (prod) 换成 (sum) 或许会好些,考虑使用 付公主的背包 的方法,求 (ln)(exp)

    那么有:

    [egin{aligned} ln(1+kx) &= int (ln(1+kx))'\ &= int frac{k}{1+kx}\ &= int sum_{i ge 0} k(-k)^ix^i\ &= sum_{i > 0} frac{(-1)^{i-1}k^i}{i} x^i end{aligned} ]

    然后转化 (prod)

    [egin{aligned} prod_{k=1}^K(1+kx) &= exp(sum_{k=1}^K sum_{i > 0} frac{(-1)^{i-1}k^i}{i} x^i)\ &= exp(sum_{i > 0}frac{(-1)^{i-1}}{i}x^i sum_{k=1}^K k^i) end{aligned} ]

    如果我们能够快速求出所有的 (sum_{k=1}^Kk^i),那么就可以直接 exp 得到答案了。

    这个东西其实就是要求 (n) 个自然数幂和,可以用高斯消元或拉格朗日插值或伯努利数或斯特林数搞定,但复杂度都很高。

    考虑 (sum_{k=1}^K k^i)(i) 的生成函数。

    如果使用 OGF,那么应该是 (sum_i sum_{k=1}^K k^i x^i = sum_{k=1}^K frac{1}{1-kx}),看起来不好搞。

    如果使用 EGF,那么应该是 (sum_i sum_{k=1}^K frac{k^ix^i}{i!} = sum_{k=1}^K e^{kx} = dfrac{e^{(K+1)x}-1}{e^x-1}),可以用求逆搞定。但是分母的常数项为 (0),没有逆元。不过分子的常数项也为 (0),于是分数上下两边同时除以 (x),值仍然不变。于是我们得到了一种 (O(n log n)) 的做法。

    总复杂度:(O(n log n)),常数顶个 (log)

    Prime Flip

    (10^{100}) 枚硬币,其中 (n) 枚硬币正面朝上,分别在 (x_1,x_2,...,x_n),其余反面朝上。

    每次可以选择一个区间 ([l,r]),将区间内所有硬币翻转,要求 (r-l+1) 为奇素数。

    求最少需要多少次才能使得所有硬币反面朝上。

    (1 le n le 100,1 le x_i le 10^7)

    区间异或可以通过经典套路差分转化为两点异或。(注意不是前缀和,区间加在前缀和数组上的表现为加等差数列)而差分后为 (1) 的位置不超过 (2n)

    不难发现我们的所有决策都可以看作两个两个地消掉。那么我们可以预处理出来两两之间消掉的最小代价,那么跑一遍一般图最大权匹配即为答案(但是我不会)。

    通过手玩不易发现,对于两个相距 (d) 的点,如果 (d) 为奇素数,那么代价为 (1);如果 (d) 为偶数,那么当 (d > 4) 的时候,根据哥德巴赫猜想(一个 (>4) 的偶数一定能拆成两个奇素数的和)在 (10^7) 内被验证为正确,可得代价为 (2),而 (d le 4) 的偶数也不难得到代价为 (2);如果 (d) 为奇合数,那么代价为 (3)(至少可以先加 (3) 变为偶数,然后偶数代价为 (2)

    注意到奇数的情况两点一定一奇一偶,偶数一定同奇偶。于是贪心:尽可能的用奇素数,然后用偶数,最后用奇合数(这个最多只会用一次)。这个不难证明。

    而奇素数的情况因为一奇一偶,可以通过二分图匹配来得到。剩下的就好说了。

    地震后的幻想乡

    给定一张 (n) 个点 (m) 条边的无向图,每条边的边权在 ([0,1]) 内均匀随机分布。求最小生成树的最大边权。

    (1 le n le 10,1 le m le frac{n(n-1)}{2})

    为什么一到状压我就不会啊/kk 不过这道题是卡在了概率期望那里了。

    首先有一个结论:(n)([0,1]) 均匀随机变量的第 (k) 大的期望为 (frac{k}{n+1}),证明见这里或者这里。最好当常识背过。

    那么答案就是:

    [sum_{i,边的相对大小} P(选前i小的边后恰好连通) imes frac{i}{m+1} ]

    那么考虑如何求 (sum_{边的相对大小}P(选前i小的边后恰好连通))。首先“恰好”不好处理,一步差分后转化为 (P(选前i-1小没连通)-P(选前i小还是没连通))。考虑求 (P(选前i小没连通))。考虑从小到大加边,由于所有(边集)从空集到大小为 (i) 的方案数都是等概率的(虽然可能克鲁斯卡尔的时候我们可能加了一半停下来了,但是如果从”从小到大加边“的角度看确实是这样的),且总方案数为 ({m choose i}),那么我们只需要求出从 (m) 条边中选 (i) 条边,且这 (i) 条边连通的方案数。这个相比之前的过程来说要简单得多。

    类似有标号无向连通图计数的方法,我们设 (f(S,i)) 表示选了 (i)(S) 内的边,让 (S) 连通的方案数。其中 (S) 为点集。类似地,设(g(S,i)) 表示选了 (i)(S) 内的边,让 (S) 不连通的方案数。那么有 (f(S,i) + g(S,i) = {c(S) choose i}),其中 (c(S))(S) 内的边数。现在我们只需要挑一个好算的来计算即可。

    注意到 (g(S,i)) 好递归计算。枚举 (S) 中编号最小的那个点所在连通块及其内部的边数。那么有转移:

    [f(S,i) = sum_{lowbit(S) in T subset S} sum_{j = 0}^i g(T,j) {c(S-T) choose i-j} ]

    然后答案即为:

    [sum_{i} frac{i}{m+1} cdot (frac{g(U,i-1)}{{m choose i-1}} - frac{g(U,i)}{m choose i}) ]

    其中 (U) 为全集。

    复杂度:(O(m^23^n)),不过有个小常数。

    加特林轮盘赌

    (n) 个人轮流做游戏,从 (1) 开始,每个人有 (p) 的概率死亡出局,有 (1-q) 的概率存活。一直到只剩下一个人。

    给定 (n,p,k),求最终第 (k) 个人存活的概率。

    (1 le n le k le 10000,0 < p < 1)

    难点在于前缀和优化。

    (f(n,i)) 表示 (n) 个人的游戏中第 (i) 个人最终存活的概率,(g(n,i))(n) 个人的游戏中 (i) 为第一个死亡的人的概率。

    那么有:

    [g(n,i) = (1-p)^{i-1}psum_{jge0} (1-p)^{nj}\ = frac{(1-p)^{i-1}p}{1-(1-p)^n}\ f(n,i) = sum_{j < i} g(n,j) imes f(n-1,i-j) + sum_{j > i}g(n,j) imes f(n-1,n+i-j) ]

    由此得到一个 (O(n^3)) 的做法。

    考虑前缀和优化。一般情况下转移中含有类似 (f(i-j)) 的东西是不好前缀和优化的。但是发现 (g(n,j) cdot (1-p) = g(n,j+1)),即可以通过乘 (1-p)(g) 的下标统一加 (1)。那么就可以快速求 (i) 增加 (1) 的结果了。

    game

    (n) 个点,一部分为黑点,剩余为白点。有 (m) 条无向边,每条边连接着一个黑点和一个白点(即图有二分图性质)。两人博弈。

    随机钦定某个点为起点,先后手轮流操作,每次沿着一条无向边走到一个之前没有到过的点。没法走的人输。

    对于每个点,询问以这个点为起点,是否先手必胜。

    (1 le n,m le 20000)

    不难推测每个点是否先手必胜和二分图有关。

    有一个结论:如果一个点是二分图的必须点,即每一种最大匹配方案中这个点都被匹配了,那么这个点先手必胜,否则先手必败。

    证明必须点先手必胜:先手从这个点 (x) 向匹配边走到另一个点 (y),如果 (y) 没有其余边,则先手胜;否则后手从 (y) 走向 (z),那么先手可以从 (z) 走向 (z) 的匹配边。不难证明 (z) 一定有匹配边,否则 (x -y) 可以被替换为 (y-z)(x) 不是必须点。

    证明非必须点先手必败:先讲最大匹配的图调整为 (x) 没有匹配的情况。如果 (x) 没有出边,则先手必败;否则,假设 (x) 有一条出边为 (y),那么后手可以走 (y) 的匹配边。不难证明,(y) 一定有匹配边,否则存在 (x - y),当前匹配不是最大匹配。

    于是问题转化为找出二分图的所有必须点和非必须点。

    用网络流随意找一组最大匹配。因为非必须点要么是没匹配的点,要么是可以被其余点替换的点。于是从 (s) 出发尝试增广(肯定会失败,但是可以知道哪些点可以被增广),经过的左部点为非必须点;从 (t) 出发尝试反向增广,经过的右部点为非必须点。

    Nezzar and Hidden Permutations

    要求构造两个长度为 (n) 的排列 (a_i,b_i)。给定 (m) 条限制 ((p_i,q_i)),要求在这两个排列中 ((p_i,q_i)) 的大小关系相同。要求最大化 (a_i ot= b_i)(i) 的数量。

    (1 le n,m le 5 cdot 10^5, tl = 5s)

    首先可以把问题抽象成图论模型。排列的每个位置对应一个点,每条限制对应一条无向边。我们要给每个点赋 (a_i,b_i) 两个值,要求 (a_i,b_i) 各自构成排列且 (a_i = b_i) 的点尽可能小。

    不难发现,如果一个点满度了,它和其它的所有点都有连边,那么这个点一定只能 (a_i = b_i)

    现在我们只需考虑不存在满度点的情况了。可以证明,一定存在一种方案使得这些点 (a_i ot= b_i)

    Solution1(jzp)

    考虑到如果 (u,v) 没有连边,那么我们可以将 (u) 设为 (1),将 (v) 设为 (2),并且在第二个排列中交换这两个数,然后删除这两个点。然后就可以递归到一个点数为 (n-2) 的情况了。(注意,这里的 (1) 指的是最小的值)

    然而发现这样会出错,有可能删去这两个点以后,其它点中存在一些点就变成了”满度“点。那么考虑优先删除点度数较大的点。

    找到当前点度数最大的那个点 (u)。如果点度数为 (n-2),那么一定只含有一个没有和它连边的点 (v)。如果我们按照上面的方法做的话,可能存在其它点 (p),原来度数为 (n-2),没有和 (v) 连边,删除 (u,v) 之后 (p) 就成满度点了。那么我们找出所有的这样的 (p),将 (u,p_1,p_2,..,p_k,v) 设为 ((1,2,3,...,k+1,k+2))((2,3,4,...,k+2,1)),然后删除掉这些点。可以证明这样做一定合法,且不会再有其余的点的度数变为 (n-2)

    如果点 (u) 度数为 (n-3),那么会有两个没有和它连边的点 (v,w)。这时我们尝试按照开头的方法做,删去 (u,v) 的话,可能会有 (w) 的度数为 (n-3),且 (v,w) 之间没有连边,删去 (u,v)(w) 成为满度点。这时我们假装连上 (u,v),问题变为 (u) 的度数为 (n-2) 的情况了。

    如果点 (u) 度数小于 (n-3),那么剩余点的度数至多为 (n-4)。找到任意一个没有与 (u) 连边的点 (v),按照开头的做法删去 (u,v) 即可。不难证明不存在剩余点的度数变为 (n-1) 的情况。

    复杂度:(O((n+m) log n)),代码量和常数巨大

    Solution2(std)

    找到任意一个补图的生成森林。不难发现每个连通块大小至少为 (2)

    对于一个菊花(star),那么找到其中心 (u),其余点 (p_1,p_2,...,p_k),可以设 (u,p_1,p_2,...,k)((1,2,3,...,k+1))((k+1,1,2,...,k))。然后可以把这个菊花删掉递归子问题。

    如果我们能够将每一棵树划分为若干大小至少为 (2) 的菊花,那么就可以依次删除了。

    具体来说,找到一个没有被划分过的点 (p),如果 (p) 的邻居中存在没有被划分过的点,那么可以将 (p)(p) 的所有没有被划分过的点都划分为一个菊花;否则,(p) 的邻居都为划分过的点,且都不是菊花的中心。找到任意一个邻居 (q),如果 (q) 所在菊花大小为 (2),那么将 (q) 设为菊花的中心,将 (p) 划进去;否则将 (q)(q) 所在菊花中删除,(p,q) 组成一个菊花。

    复杂度:(O((n+m) log n)),瓶颈在于找到补图的生成森林。

    附上std的找补图生成森林的代码:

    set<int> rv; // remained vertices
    set<int> g[maxn]; // original graph
    set<int> t[maxn]; // dfs tree
    void dfs(int u){
        rv.erase(u);
        int crt=0;
        while (1){
            auto iter=rv.upper_bound(crt);
            if (iter==rv.end()) break;
            int v=*iter;
            crt=v;
            if (g[u].find(v)!=g[u].end()) continue;
            t[u].insert(v), t[v].insert(u);
            dfs(v);
        }
    }
    ...
    for (i = 1 -> n) rv.insert(i);
    while(rv.size() > 0) dfs(*(rv.begin()));
    

    寿司晚宴

    (n) 个点,要取 (m) 次,第 (i) 次取可以选择一个位置 (p)(可以为空),向左或向右取第一个点,取完后那个位置就为空了。要求每次都必须取到点。给定 (n,m),问合法方案数。

    (1 le m le n le 10^5)

    接链成环。我们在序列后面新加一个虚拟节点,然后把第一个点和最后那个虚拟节点连起来成一个大小为 (n+1) 的环。每次我们可以选择一个位置顺时针或者逆时针选一个位置,取点,这样的话每次都能取到一个点。但是我们要求不能取到虚拟节点,于是我们可以这样看:一开始暂时不确定环的编号起点,随便编一个;然后开始取,最终从剩下的 (n-m+1) 个点中钦定一个作为虚拟节点。这样的话方案数为 (2^m(n+1)^m(n-m+1)),但是发现每一个起点都会把答案算一遍,于是最终除一个 (n+1),即答案为 (2^m(n+1)^{m-1}(n-m+1))

    复杂度:(O(log m))。理解的还不是很透。

  • 相关阅读:
    Oracle Instant Client 配置
    释放至强平台 AI 加速潜能 汇医慧影打造全周期 AI 医学影像解决方案
    Analytics Zoo Cluster Serving自动扩展分布式推理
    基于时序数据,推动智能运维发展
    助力用户选择更优模型和架构,推动 AI机器视觉落地智能制造
    英特尔与 Facebook 合作采用第三代英特尔® 至强® 可扩展处理器和支持 BFloat16 加速的英特尔® 深度学习加速技术,提高 PyTorch 性能
    如何无缝地将人工智能扩展到分布式大数据
    Burger King使用RayOnSpark进行基于实时情景特征的快餐食品推荐
    如何往Spark社区做贡献,贡献代码
    开源:从社区到商业化
  • 原文地址:https://www.cnblogs.com/JiaZP/p/14253200.html
Copyright © 2011-2022 走看看