滑动窗口求极值。
1 | int l = 0, r = 0; |
有长度限制的最大连续子序列和
单调队列维护前缀和的不减单调队列,队首元素为最小值标号,则此时的答案最大。
1 | for (int i = 1; i <= n; i++) pre[i] = pre[i - 1] + a[i]; |
1 | int l = 0, r = 0; |
单调队列维护前缀和的不减单调队列,队首元素为最小值标号,则此时的答案最大。
1 | for (int i = 1; i <= n; i++) pre[i] = pre[i - 1] + a[i]; |
1 | struct complex{ |
最开始想肯定是维护一个递增的序列,后面的只保留一个即可,但是测一测并不对,然后发现前面维护递增的高度的同时可以在维护每列多用了了多少块,这些多用的块可以放在后面,让一列实际上可以全部清空。
拆出每个数的因子然后dp。
时间复杂度: O(n√n)
交互题,有一棵 n 个节点的满 k 叉树,标号 1−n,现在你需要找到树的根。
每次你可以询问两个点 a,c 之间的路径上是否含有 b。
首先想到必须要任取两个点,然后枚举其他点看是否在这条路径上,然后我们注意到任取两个点之后,我们很能够不断调整将这两个点移动到叶子上去。
因此,我们可以在 O(n) 次询问内得到一条叶子结点之间的路径,然后我们又可以知道如果这条路径的长度为 2∗dep−1,那么他必定经过根节点,然后对于根节点,恰好有 dep−2 个节点在分别在两个叶子结点中间,因此如果我们能获得一条经过叶子结点的路径,就能很快计算出他的根节点。
这里我一开始考虑是不断调整,但是这个复杂度很玄学?
实际上,根据其他人提交的代码我们可以注意到一个事实,在树上任取两个点,这两个点 lca 不是根节点的概率实际上是 k−1k,所以直接随机即可。
这场题怎么这多锅?题面看起来怎么这么麻烦啊,自闭 T^T。
字符串删掉至多一个字符时得到的串中,输出字典序最小的那个。
显然必须删一个,从左往右必须单调不减,找到第一个断开的位置或者删除最后一个位置即可。
日常 B 翻车?
一开始觉得找到最小素因子,输出 n / 最小素因子 即可,实际上最小素因子会改变。
在第一次删除最小素因子后,n 变成了一个偶数,这时最小素因子不会再次改变。
ans=1+(n−mindivsor)2。
解一元二次方程,这 BC 位置是不是该换一换啊?
给一个无向带权联通图,记 di 表示 1 到 i 的最短路长度,将图上的边删到至多 k 条,最大化最短路长度不变的点的数量。
感觉上跑一个 dijkstra,然后把出现次数最多的扣出来?挂了,直接在最短路图上 dfs 输出 k 条边就行了?
给一棵树,每个节点初始值为 0。
定义 k−subtree(i) 表示 i 的子树中深度不超过 dep[i]+k 的顶点构成的树。
m 次询问将 d−subtree(v) 内所有顶点加上 x,输出所有点权。
离线询问,注意到每个顶点的权值只与其祖先有关,所以可以用树状数组,对深度维护的前缀和。
仔细读题。
给定一个区间 [1,n],两个人分别选定一个数 a,m,在范围内随机生成一个数 x,距离这个数近的胜利,距离相等对方胜利。
已知区间长度和对方的选择,问自己选择什么获胜概率最大。
计算一下可以得到:2(a−m)x>(a−m)(a+m),对 a,m 大小关系讨论后,发现 a 只会取 m+1 和 m−1,分类算一下即可。
注意特判 n=1。
给一个字符串,每次将最前面的 “..” 合并为 “.”,询问将某个位置永久修改成另外一个字符时的操作次数。
分类之后进行修改,讨论一下可以 O(1) 更新答案。
树上启发式合并。
树上启发式合并是用于解决一类树上无修改的子树信息离线查询问题的一种有力工具。
其时间复杂度由轻重链剖分来保证,轻儿子的大小会小于父亲大小的一半,也就是一条链上最多有 log 数量级的轻儿子。
树上启发式合并,优化自一个 O(n2) 的想法,对于一个节点,递归计算这棵子树,更新答案,然后消除其所有子树的贡献,防止儿子之间相互影响。
但是,这样做实际上有些答案的贡献是多删除的,应该保留一些贡献不删除,根据树链剖分选择保留重儿子的信息回溯到父亲节点。
之后我们得到了这样的过程,递归进入一个节点,先计算其轻儿子的答案,最后计算重儿子,之后将重儿子的信息上传到父亲,结合这些信息再递归计算这棵子树的轻儿子位置,得到该节点的答案,最后根据递归参数调整是否要上传子树信息。