博主是大鸽子,不定期更新。只要相信自己是鸽子,就可以心安理得地咕咕咕~
10.29
智商检测题 \(\times 4\)。
T1
排列形成若干环,求环数 \(\le k\) 的方案数。
直接 DP,\(f(i,k)\gets f(j,k-1)\times {i\choose j-1}\times (i-j-1)!\),然后拆开组合数可以前缀和优化,\(\mathcal O(nk)\)。
后来发现就是个第一类斯特林数列前缀和。
T2
如果一个子串 \([l,r]\) 满足 \(s_l=s_r\),那么其翻转一定会被子串 \([l+1,r-1]\) 的翻转表示。
T3
转化到 \(4\) 个点的图上,发现有很多边重复。重边中奇数条边可以缩为一条,偶数条可以把最小边拆出来缩为两条(最小边可能不走);子环缩为一条。
最多 \(16\) 条边,就可以状压或者爆搜了。
T4
答案有单调性,先二分。然后贪心的去匹配,将所有人和卷轴排序,从左往右每个人一定是取最左端的若干卷轴,看是先往左走还是先往右走更优。
10.31
T1
可以线段树模拟,区间加、区间赋值、区间求和。有点卡常。
更优秀的做法是,每次操作会删去若干空格、产生一个空格,用一个栈模拟,同时记录位置和空格长度来计算贡献。
T2
对于每种结果对应的区间集合,我们再最小的区间统计贡献。
补集转化一下,求无贡献的区间,充要条件为:左端点是区间最小值或者右端点是区间最大值。
单调栈可以求出满足其中之一的。为了不算重两者都满足的,在统计后者的时候同时再维护一个单调栈,用来求某个区间内是区间最小值的左端点数。
T3
长为 \(b+1\) 的合法区间中有且仅有一个数出现两次。
滑动这个区间,弹出的数若只出现一次,新加入的数只能与其相等;若出现两次,新加入的数任意。
那么记录重复的数的第一次出现次数,可以有 \(\mathcal O(n^2)\) 的 DP。
观察 \(f(i,*)\to f(i+1,*)\) 的转移过程,发现是整体平移和近似的全局加,用队列和一个全局加标记模拟即可 \(\mathcal O(n)\)。
T4
每次询问都计算一遍,枚举强制经过的边统计方案数进行暴力容斥,没啥思维水平。
有大量细节,大概是:不要算上大小为 \(2\) 的环;由于翻转同构最后要 \(\div 2\);注意判出现环和所有边构成一个环的情况。
复杂度 \(\mathcal O(m^22^m)\)。
11.2
心情不好,不写了口胡一下不写代码。
T1
后三个可以从低位到高位递推。
第一个使用万能的折半搜索。
T2
手推一下较小的情况,可以发现强的和强的内斗、弱的和弱的内斗更优。然后“我”的策略是尽量先打弱的。
若弱者有奇数个,挑一个和“我”打,其余两两配对;若弱者有偶数个,挑一个和“我”打,再挑一个和强的打(会产生两个分支);强的和弱的其中有一个为 \(0\) 当然没得选咯。
写个记忆化搜索,每一层的强、弱者数量都只有两种可能,状态量是 \(\mathcal O(n)\) 的(有 \(2^n\) 个人)。
题解的 \(\mathcal O(n^2)\) 咋分析的?教教!
T3
美国数学竞赛 ELMO2017 的一道题。
设 \(m\) 为 \(1\) 的个数,出题人说一定可以把每一段的和控制在 \([m,2m)\) 之内,并且唯一的反例是 \(\texttt{11111}\)。
那么可以做 \(\mathcal O(n^3)\) 的 DP。
出题人有个结论是:一定存在一种合法方案每一段长度不超过 \(4\)。证明就是 ELMO 的官方解析的事儿了,可以去问 @YCS_GG。口胡出题人过分了。
然后就 \(\mathcal O(n^2)\) 了,再用 \(\texttt{std::bitset<>}\) 优化就过了。
啥破题啊,摆一堆结论让谁猜去啊。
T4
整出树的欧拉序,每个状态唯一对应欧拉序上的一个位置。每条边只会被断掉一次,每个活着的人一轮一定会断掉一条边。那么拿 splay 森林维护欧拉序,断边就是提取子树,从欧拉序上提取区间,注意要删去多出来的一个无用点。复杂度 \(\mathcal O(n\log n)\)。
simple 的 idea,但是非常难写。
11.3
T1
所有数都分解个质因数就完了。
T2
二分然后 \(\mathcal O(n^2)\) DP 出最少修改个数。
T3
CF280D,线段树模拟费用流。
好像也可以用堆写。
T4
每一位独立,分开考虑,矩阵有结合律,线段树。
11.6
T1
- 做法 1
二分套树状数组上二分可以求出每个点作为中位数最大的能选的个数,每次询问再二分一下最大的答案,复杂度 \(\mathcal O(n\log^2n)\),比较卡常。
- 做法 2
单 \(\log\) 做法是基于选的数量从小到大,最大的中位数位置是单调不增的。边单调移动指针边 check,主席树和树状数组均可。
T2
- 做法 1
跑 Dijkstra,每次比较 \(\mathrm{dis}\) 时不显示的记录全部路径,而是记录更新它的前驱点 \(\mathrm{pre}\) 及倍增,以及路径的哈希值。比较时先比较二进制串长度,长度相同时倍增到第一个不相同的位置进行比较。复杂度 \(\mathcal O(m\log^2 n)\)。
注意要用 \(\texttt{std::multiset<>}\) 代替堆,避免堆中无用点的影响。而且还需要卡卡常数。
- 做法 2
正解是分层 BFS,每次取出所有距离相同的点,先更新 \(0\) 边,再更新 \(1\) 边,复杂度 \(\mathcal O(n+m)\)。
T3
假期望,计数带权方案数。
- 做法 1
考虑一个序列应当在何处被计算贡献。将序列从小到大排序,前缀和,若一个点的前缀和 \(\le m\),就计算一次。
那么枚举每个点作为被计算的点,为了不算重,钦定右面的排序后都在它前面,并且一边是 \(f\) 一边是 \(s\),
\[\sum_{v=1}^A\sum_{i=0}^{n-1}\sum_{j=0}^{m-v}f(i,v-1,j)\times s(n-i-1,v,m-j-v) \]其中 \(f(i,j,k)\) 表示 \(i\) 个数,其中所有 \(\le j\) 的数和为 \(k\) 的方案数,\(s(i,j,k)=\sum_{l=0}^kf(i,j,l)\),可以直接 DP。
复杂度 \(\mathcal O(nm^2)\)。
- 做法 2
考虑直接枚举最大的被选的数,和选了多少次,序列分成三部分进行多重集排列,
\[\sum_{v=1}^A\sum_{i=0}^{n-1}\sum_{j=1}^{n-i}h(i,j-1,m-j\times v){n\choose i}\sum_{k=j}^{n-i}{n-i\choose k}(A-v)^{n-i-k} \]其中 \(h(i,j,k)\) 表示 \(i\) 个 \(\le j\) 的数和为 \(k\) 的序列方案数。
发现我们不需要乘权值 \((i+k)\),因为这样本身是会算重的,一个序列会在每个被选的权值算上被选个数次。
计算 \(h\) 同样可以直接 DP,或者枚举哪些数超过 \(j\) 进行容斥:
\[h(i,j,k)=\sum_{l=0}^i(-1)^l{i\choose l}{k-l\times j\choose i} \]单点计算 \(h\) 是 \(\mathcal O(n)\) 的,枚举 \(v,j\) 是调和级数,总复杂度 \(\mathcal O(nm\log m+n^2m)\)。
T4
先给 \(T_2\) 枚举一个根,然后在 \(T_1\) 状压 DP。最后还要除掉 \(T_2\) 自同构的方案数。实现复杂度 \(\mathcal O(nm^22^m)\) 或者 \(\mathcal O(nm^23^m)\)。
11.6
T1
状态里记录 \(\mathrm{cnt}_0(i)-\mathrm{cnt}_1(i)\) 的最大值和最小值与当前值的差,随便 DP 一下。
T2
把车上的人的目的地都压进状态里。
一个性质是,如果某一时刻有一个上车,车上达到 \(4\) 个人,那么去下一个上车点之前只能先去往某个目的地。所以只需要记 \(3\) 个人的状态。
以每次到达一个上车点为一个时间点,逐个人转移,也不需要记当前的位置。
细节很多。
T3
折半。
T4
flow?咕咕咕。
11.7
T1
难点在于看懂题,树上随便搞搞。
T2
线代 nb 题,太难了不会。
T3
推式子 nb 题,太难了不会。
T4
最小树形图?直接上 tarjan 也是可以做的,可以用暴力代替可并堆,\(\mathcal O(n^2)\)。
有更为优美的 DP 做法。首先只关注每个点最小的入边,形成若干基环树。
如果占领了基环树环上的某一点,整个基环树的每个点也就通过最小入边被占领;如果占领非环上的点,其子树内的点也是跟随其通过最小入边被占领。
所以最优占领顺序是分段的,其中每一段是一棵子树或基环树。并且一个子树/基环树的占领后对其他点的影响取决于编号最大的点。
由于题目保证了除最小入边以外有 \(t_{i,j}\ge t_{i,j+1}\),发现如果某一时刻 \(n\) 点被占领了,此时所有未被占领的基环树一定是由 \(n\) 点占领环上某一点。
考虑怎么排列 \(n\) 点之前的占领顺序,性质是:设 \(\mathrm{maxid}(u)\) 表示 \(u\) 子树/基环树内编号最大的点,\(n\) 点之前占领的每一段的 \(\mathrm{maxid}(u)\) 是单调递增的。证明,如果存在相邻两段 \(u,v\) 满足 \(\mathrm{maxid}(u)>\mathrm{maxid}(v)\) 那么将 \(v\) 调整至 \(n\) 点之后被占领,答案只可能更优。
这样直接 DP 是 \(\mathcal O(n^2)\) 的。
11.8
T1
两个等差数列的交也是等差数列,公差为 \(\mathrm{lcm}(d_a,d_b)\),可以第一个交点可以暴力找,因为范围大概也是 \(\mathcal O(\mathrm{lcm}(d_a,d_b))\) 的。
边角细节懒得想,只能靠对拍咯。
T2
最优策略一定是,每次先把头尽量往右挪,然后把所有腿尽量往右挪。
T3
同余最短路,只要点按数字位数从小到大、出边按 \(0\dots k-1\) 的顺序更新,跑 BFS,就是最优的。
记不下答案,需要记录转移前驱点。
T4
\(A_x\) 集合的操作可以用带权并查集维护,\(B_x\) 也是在并查集上记录时间戳。
\(B_x\) 对 \(A_x\) 有影响,但是每个点只有最后一次的赋值操作是有用的。离线下来处理每次询问点的最近一次赋值操作,然后拆成两次询问解决。
复杂度 \(\mathcal O(m\log n)\)。
11.10
T1
答案是 \(s,t\) 最短路,然后就显然辣。
T2
散了吧散了吧,要生成函数的。
T3
排序后,选取子序列合法只需要保证相邻两项异或值 \(\ge x\),证明只要讨论一下最高的不同位。
然后 01 trie 优化一下。
T4
这个容斥真的康不懂啊。 什么嘛,这个 T4 比 T2 阳间多了。
首先可以转化一下,操作 \(k\) 次能够得到的排列的条件为,最长上升子段的长度 \(\ge n-k\)。
那么求最长上升子段的长度 \(\le n-k\) 的排列数,考虑容斥,即总排列数 - 钦定 \(1\) 个长为 \(n-k\) 上升子段的排列数 + 钦定 \(2\) 个长为 \(n-k\) 上升子段的排列数……
钦定的上升子段可能会相交,需要合并。“合并”的意思大概是,一个长为 \(n-k+2\) 的上升子段,可以是钦定了的两个 \(n-k\) 的上升子段相交产生的,也可以是钦定了的三个 \(n-k\) 的上升子段相交产生的。那么这个 \(n-k+2\) 的子段的容斥系数应当是钦定 \(2\) 段的容斥系数与钦定 \(3\) 段的容斥系数之和。
根据合并的性质,这个容斥系数(设为 \(f_i\))可以 DP,\(f_1=1,f_{n-k}=-1\),然后有
\[f_i=-1\times \sum_{j=1}^{n-k-1}f_{i-j} \]然后做 \(\mathcal O(n^2)\) 的 DP 来将若干上升子段拼接出一个排列,在 DP 时同时计算多重集排列 \(\frac{n!}{\prod a_i!}\) 的分母,设为 \(g_i\),
\[g_i=\sum_{j=1}^i g_{i-j}\times f_j\times \frac{1}{j!} \]复杂度可以做到 \(\mathcal O(n^3)\) 了。
进一步观察,\(f_i\) 的值非常稀疏,有值的地方只有
- \(f_{(n-k)\times t}=-1\);
- \(f_{(n-k)\times t+1}=1\);
只考虑这些地方,复杂度就是 \(\mathcal O(n^2\ln n)\) 啦。