07 2020 档案
摘要:类似没有上司的舞会,找到环上一点,将环断开,强制是否选择root,做树形dp #include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=1e6+1e5; int h[N],ne[N*2],e[N*2]
阅读全文
摘要:本题是基环树模板题,但是有一点要注意,特判两元环是必要的 因为两元环中,我们要选权值大的两条边组成的直径,而多元环则不用在意,因为每两个点之间只有一条边 #include<bits/stdc++.h> using namespace std; typedef long long ll; const
阅读全文
摘要:本题如果删除l-r,那么l-r+1...这些也都是满足的,因此具有单调性。 所以我们考虑枚举l,r,对于判断,维护四个数组 分别为l[],当前数出现的最早时间 r[],当前数出现的最晚时间 ll[],1-i出现的最早时间 rr[],i-n出现的最晚时间 对于满足的状态要分三种情况讨论 #includ
阅读全文
摘要:类比2019南昌区域赛c题,发现也是个二维数位dp,我们发现差值不可能超过+-1000,并且位数一共100位,因此可以列出状态方程 这题还需要考虑a<b,因此多枚举一位表示当前是否已经小于b #include<bits/stdc++.h> using namespace std; typedef l
阅读全文
摘要:学习完lyndon分解后,我们发现这个分解可以分割字符串并且分割成a[i]>=a[i+1]且每个字符串都是自己的最小后缀 因此在分解的过程中 当遇到s[j]==s[k],这说明前面都是循环的字符串,那么答案就是上一个同样位置的答案后移一个循环节长度 如果s[j]<s[k],这说明马上整串都变成一个l
阅读全文
摘要:#include<bits/stdc++.h> using namespace std; typedef long long ll; const int inf=0x3f3f3f3f; const int N=2e5+10; string s; int main(){ ios::sync_with_
阅读全文
摘要:虽然看上去需要维护两个传送门,但是其实dp状态只需要设计一个就行了,这是因为当我们使用传送门的时候,总是在当前点创建传送门,所以只 也就是只要维护另一个传送门即可 对于转移,我们首先要把任务拆分掉,因为虽然一个任务有两个位置,但是我们发现其实每一步可以看成一个任务,因为假如我在上一个任务的终点 对于
阅读全文
摘要:#include<bits/stdc++.h> using namespace std; typedef long long ll; const int inf=0x3f3f3f3f; const int N=2e5+10; int a[N]; struct node{ int cnt; node
阅读全文
摘要:首先本题是求取完全图的最小生成树,但是显然暴力不了 我们观察到任意两点之间的权值就是两个点到根节点的异或和 因此想到用Trie来维护这个操作(反正我想不到)也就是xor最小生成树 我们把每个点到根节点的异或和当做点权值,建立01Trie 这么做是为了下一步做贪心的准备,因为最小生成树其实就是用一些边
阅读全文
摘要:本质上是一个状态机模型,因为对于每个来说,只有可能存在一个篮子是由同一堆中的不同颜色构成,否则都可以转化为这一类。 因此我们枚举f[i][j]为前i个,红色果实剩余j个,之后选择是否选择产生这种的篮子进行dp转化 #include<bits/stdc++.h> using namespace std
阅读全文
摘要:题目满足单调性,考虑先二分后进行check 对于check,用树形dp来表示状态是否可达,设计d[i][j]表示以j为根节点的子树,使用了i个a边,能满足长度不超过二分答案值的离i最远距离的最小值 含义就是,对于每种合法方案,都保存最小的距离,这样对之后的状态转移的最优的。 #include<bit
阅读全文
摘要:本题没有无解情况,因为这题本质上可以通过二进制叠加,并且我们知道所有数都能被这样表示 对于有解情况,显然每次跳跃的越多越好,但是这是有限制的,一个分裂的总数不能超过当前的个数 第二个是当前分裂完后,要保证第二天分裂结果不能超过总答案,否则无法到达。 #include<bits/stdc++.h> u
阅读全文
摘要:本题询问字符串的编辑距离。 观察题目可得,插入操作是没有用的,所有插入操作都能用删除操作,并且至少不会大于。 因此我们发现,对于两个字符串使得他们相等,最小的其实就是保留lcs。 现在询问的数量很多,因此肯定考虑预处理,对于s串l-r,如果能匹配t串,那么我们需要找的是两个串最大能满足条件的lcs。
阅读全文
摘要:题目想问的是每次取一个所能取到最大的连通块,并把他们的上面每个点的权值-1,最少需要多少次操作 这题顺着做,就是每次找到最大的连通块,然后-1,之后可能出现某些连接点权值为0断开,变成多个连通块继续做。 因此考虑倒着做,我们发现,每个点作为单独的连通块做出的贡献就是当旁边的点权值为0了,因此将点的权
阅读全文
摘要:观察题目可得,所有初始位置比其他小,并且加速度也比其他小的点是永远不会成为答案的,这些点应该要删除,否则对后面求解有影响,之后会说明。 对于p相同的,只需保留a最大的即可,因为其他也不可能成为答案。如果最大的有多个,那么这个点不能成为答案,因此要把他的贡献置为0,但是这个点需要保留,因为可能影响到别
阅读全文
摘要:比赛的时候根据数据范围马上猜出了是通过轻重点分块,但是在维护set的时候犯了一个nt错误 选择了插入邻边的权值去判断第一个未出现的答案,怎么想都觉得复杂度很高。 其实可以选择先插入所有得可能答案,然后对邻边影响得答案进行删除,这样set中得第一个元素就是答案。 这题复杂度保证得原因是,通过分块,对于
阅读全文
摘要:通过领悟题意,发现本题只与关键点和他们的lca有关,因此把只需要对他们建虚树 对于dp思路,如果x不是关键点,那么观察子树中有多少需要断开的,如果超过1,那么直接断开这个点,如果等于1,先保留看看能否与后面的一起。 如果是关键点,那就必须要把当前点和子树中的所有关键点断开,首先我们知道一定存在合法方
阅读全文
摘要:虚树对于多次询问的时候有这优化复杂度的好处,其原理就是只保留有用节点和必须保留的有用节点的lca 先求一遍dfs序后,用栈模拟操作,根据lca是否在栈中确定是否要将lca加入栈,因为重构了树,因此原来的边的信息需要进行更换 对于本题,新的边其实就是路径上的边权的最小值,这是因为随便切掉一个边就能把他
阅读全文
摘要:对于这道题,可以想想对于每个b[i],a[i]中可选的位置的区间在哪,这样只要找到区间,就能知道当前可以选那几个位置断开 b[1]的开头肯定是1号位,而我们发现如果对后缀求一下后缀的最小值,这样就天然满足题目条件,我们用一个map存一下答案,就能知道b[i]是最小值的区间是哪些 因为b是单调递增的数
阅读全文
摘要:这道题需要将它抽象成图论问题,我们用二维数组f表示走到第i个关键点,绿灯还剩j秒的最小回合数,也就是一轮红绿灯 这样这个问题被抽象成了最短路的问题,因为对于同一个点来说,第一次到达某个状态肯定是最小的,因此能找到最小回合数 这道题还有一个优化是本题的边权是01的,因此可以用双端队列优化一个log #
阅读全文
摘要:同样是找dfs树,这题如果本身就是树,那么直接奇偶找大的遍历 如果是图,建立dfs树,如果全部的环都是>=k的,这样只需要找到一个环,之后隔着输出就是答案,因为这样总是能找到(k+1)/2 不然的话直接把环输出就行 #include<bits/stdc++.h> using namespace st
阅读全文
摘要:对于图建立dfs树,这样只存在树边和B边,不会存在横叉边,这也是tarjan算法的思想 建立dfs树后,我们发现任意一条B边都会生成一个环,且所有b边就是所有环 我们进行dfs栈的建立,找到如果存在满足条件的环,那就直接输出 如果不存在,我们证明肯定存在满足条件的独立集。因为根据鸽巢定理,每个点一定
阅读全文
摘要:用list维护每个节点能往外的信息,list有一个splice函数可以在list后面合并新的list,这样操作方便,之后其实就是暴力并查集+bfs,注意去重。 #include<bits/stdc++.h> using namespace std; typedef long long ll; typ
阅读全文
摘要:跑ac自动机后使用fail树建立dfs序后跑树状数组维护答案 #include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=1e6+10; struct node{ int cnt; node * nxt
阅读全文
摘要:#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=5e5+10; struct node{ int cnt; node * nxt[27]; node * fail; vector<node
阅读全文
摘要:题意是让我们求取两个字符串前缀和后缀最长的相同子串的长度的平方和 首先,查找两个字符串是否相同可以采用hash的方法,因此可以想到先对所有串的所有后缀求一遍hash 之后枚举每一个串的前缀,观察是否有后缀相同,计算每个前缀相同的后缀数 但是这个并不是答案,原因就是会有重复的被计算进来。 例如题解中的
阅读全文
摘要:题目的含义是将一个字符串的所有后缀按算出来的B函数从小到大按字典序排序 首先观察到题目给定的只有ab两个字符,并且b函数给的是与当前位置之前的最近的相同的字符的位置差值 首先暴力的思想就是对每个后缀算一遍b函数,但是发现这样是超时的,因此考虑能否进行优化 我们观察到B函数会变化的原因是,我们求到某个
阅读全文
摘要:只需要把两个串拼接起来,之后求一下后缀数组求可覆盖最长重复子串模板即可 #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<string> using namespace std; ty
阅读全文
摘要:题目求的是差分后的最长不重复相同子串 利用后缀数组求解,首先答案具有二分性,也就是重复子串越大越好 因此先二分最长长度,根据最长长度将所有后缀分组按height数组分组 依据是height数组具有排名相邻的肯定是lcp最大的,而因此如果一段相邻的height数组的大小都大于等于二分值,这说明这段排名
阅读全文
摘要:未优化 #include<bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<int,int> pll; const int N=1e6+10; char s[N]; int cnt[N],id[N],rk[N
阅读全文
摘要:无向图点双建立园方树,并且记录边在哪个点双之内 #include<bits/stdc++.h> using namespace std; typedef pair<int,int> pll; const int N=3e5+10; int h[N],e[N],ne[N],idx; int dfn[N
阅读全文
摘要:本题如果k的范围较小的话,可以使用树状数组记录答案,但是因为很大 考虑使用双指针+容斥原理。 也就是直接算整个子树的答案,之后再在枚举儿子节点的时候,把加上u-v这条边的合法答案全部清除,这样就做到了不重不漏 #include<bits/stdc++.h> using namespace std;
阅读全文
摘要:观察到如果两个位置是对称的,那么他们永远是对称的,这种输出yes和no并且没啥其他性质的,看和猜结论比较有用 因此只要把对称位置的变成一组,比较两个数组的所有组是否相等,如果相等就可以 具体证明可以看官方题解 #include<iostream> #include<algorithm> #inclu
阅读全文
摘要:本题不用边读边做,可以先读入所有边记录序号 排序后,求取m次最小生成树,参与生成的是序号小于当前次数的边 #include<iostream> #include<algorithm> #include<stack> #include<vector> #include<cstring> #includ
阅读全文
摘要:先求一下lca,之后比较一下给定两点的lca与所求点的关系后分类讨论 #include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=2e5+10; int h[N],ne[N],e[N],idx; int
阅读全文
摘要:看到最小最大,显然是经典二分 因此只需要枚举最大距离进行check 如果能存在k组或以上能满足组间距离大于等于mid 那么就可以放大,否则缩小 #include<iostream> #include<algorithm> #include<stack> #include<vector> #inclu
阅读全文
摘要:只需要用二进制来表示50个数,这样不会超过ll范围 之后按照dfs建树后建线段树维护 #include<iostream> #include<algorithm> #include<stack> #include<vector> #include<cstring> using namespace s
阅读全文
摘要:因为题目已知至少要k-2个 假设我们取了k个,使得答案最大 那么因为对于每个数来说至少k-2个数在这位是1 因此我们只要任意选三个数,都能保证在每一位上都有至少一个数为1 #include<bits/stdc++.h> using namespace std; typedef long long l
阅读全文
摘要:可以不用建字典树 其实字典树的新增节点大小就是排序后的字符串数组按序与前一个的最大后缀 但是本题的每个字符不只一位并且卡了点内存,考虑建立结构体存储 插入和删除可以维护一个set来找位置,算法比较简单,代码很蠢 #include<bits/stdc++.h> using namespace std;
阅读全文
摘要:如果好人和坏人挨在一起肯定不行 否则讲坏人周围的一圈全部围起来,这样是最优的 之后从n,m处看看能否经过所有的好人 #include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=6e5+10; char
阅读全文
摘要:点分治模板题,一般用于树上路径统计 点分治基本套路: 将信息化为通过根节点以及在子树中的信息 这样使用一个solve来表示通过根节点的 之后将根节点vis==1递归子树 因为一般来说是无根树,并且为了保证有log层,因此子树中的信息通过寻找重心来做 每次统计完通过根节点后,需要重新计算sz信息,因为
阅读全文
摘要:用线段树维护区间剩余的最大值,这样可以辅助二分,越左越好 对于用完k堆的,直接将他的值变为0即可 #include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=6e5+10; struct node{ i
阅读全文
摘要:#include<iostream> #include<queue> #include<map> #include<vector> #include<cstdio> #include<algorithm> #include<stack> #include<cstring> using namespa
阅读全文
摘要:对于01背包来说,因为每个物品先用和后用是没有区别的 因此满足交换律,对于增加一个w,他多出的方案数就是i-w转移而来 对于减少一个w,某个位置i(i>=w)他在没有w之前的方案就是从i-w且f[i-w]处也没有使用的位置转移而来 因此使用从头往后的完全背包的递推方式可以减去 #include<io
阅读全文
摘要:写的略微复杂了一些,分了很多种类。 首先肯定只能写一次建树之后进行分类讨论查看位置 #include<iostream> #include<queue> #include<map> #include<vector> #include<cstdio> #include<algorithm> #incl
阅读全文
摘要:显然高位越高越好,因此从高位往地位计算,判断当前位填0或者填1 #include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=3e5+10; const int mod=1e9+7; struct nod
阅读全文
摘要:这道题的矩阵需要转化一下思路,转换成邻接矩阵,也就是看成某个点与别的点的连线 因为每个点只和别的点有且只有两条线,因此每个点都在一个环中 这个有两种情况,一种是重边,也就是两点间是一个环,其他就是随意的 因此可以通过组合数公式推出dp方程 #include<bits/stdc++.h> using
阅读全文
摘要:用二进制压缩表示每一门科目有多少班级要考 之后枚举需要靠的科目,用二进制来控制一天之内能考的不冲突的科目 值得一提的是,虽然这样对于每一天可能并不是最佳利用的,但是答案确是最优的 因为我们保证了最后的结果是不互相冲突的,如果日子能够压缩,那么其实代表某一天的科目能放到其他天,但是这样是不存在的,否则
阅读全文
摘要:概率+暴力dfs 可以暴力枚举所有的状态,判断是否成立,对于每个状态,记录抽到这个状态的概率,如果能成功,就在答案上加上这个概率 #include <cstdio> #include <algorithm> #include<iostream> using namespace std; const
阅读全文
摘要:思维题,题目限制了在一个长度为k的滑动窗口内必须要有l个数 因此所有%k相等的位置的状态是固定的,否则两个k中的个数就不相等 因此只需要把%k个相加,之后在k个中选最大的l个就行 #include<bits/stdc++.h> using namespace std; const int N = 1
阅读全文
摘要:题意:给定一个字符串,每个操作1修改字符串上的某个值 2.给x,y,询问以x开头和以y开头的两个后缀字符串的最长前缀的大小。 经典的线段树维护hash值,之后对于每个询问,用二分查询答案,带了两个log 比赛的时候一直被卡,结束后加了一行如果第一个字母不等就略过的优化就卡过了,太伤了。 #inclu
阅读全文
摘要:因为我要目标值和真实值相同,所以肯定要按目标值大小排序,从小往大排,否则直接就冲突了 之后对于每个节点维护一格mx表示当前周围被填了的mex值,之后对比可以知道是否成功 #include<bits/stdc++.h> using namespace std; const int N=1e6+10;
阅读全文
摘要:这题的rotate操作其实就是暗示可以把某一个数提到最前面 因此本题其实就是求取最长公共子序列 但是有个问题当转移遇到s[i]==t[j]的时候,不能直接转移,因为只有当他二十六个字母的后缀数组全部比t串大时才可以转移,否则如果匹配了当前两个 没有办法把后面的提上来变成相等 #include<bit
阅读全文
摘要:对于一些不符合的点来说,肯定是被他的父节点上权值最小的点转换最好。 首先我们先排除不可能情况也就是01不等 之后发现,交换完两个数后,0不符合的和1不符合的个数各自-1,因此不会影响其他交换 因此我们维护一个最小值,表示父亲节点的最小值,如果这个值比当前节点小,那么显然在子树内部交换更好 之后只要d
阅读全文
摘要:基本建图套路,从单词头向单词尾连一条边,答案就是是否存在一条欧拉路径 #include<bits/stdc++.h> using namespace std; const int N=2e5+10; int p[N]; int din[N],dout[N]; int st[N]; int find(
阅读全文
摘要:模板题,但是有大量重边和自环,数据很坑,需要加引用优化 #include<bits/stdc++.h> using namespace std; const int N=4e5+10; int h[100010],ne[N],e[N],idx; int ans[N]; int used[N]; in
阅读全文
摘要:首先想到如果将mod的顺序变化了一下,如果答案肯定不变,那么所有数必须要是最小的数的倍数。并且题目已知数列递增。 这是因为如果模数没有倍数关系,这就会破坏模的数据,可以通过在纸上举例子得出 因此本题答案只跟最小的数有关,枚举最小的数,之后就是在倍数中取k-1个,根据逆元组合数预处理得解 #inclu
阅读全文
摘要:本题是在DAG上求取最多的两两不相连的点 我们知道的是,所有某条路径上的点都是能看的见的 因此只有求出最小路径重复点覆盖,这样每条路径的起点就是不会被别的点走到,否则这条路径没有意义。 经过传递闭包后变成最小路径覆盖,而这个已经证明为总点数减去二分图的最大匹配(这个是特殊的,两方分别为出度和入度)
阅读全文
摘要:比较容易看出是最小点覆盖问题,并且本题因为只有两种机器,所以是二分图问题,将对应的任务的两种机器连边 答案就是求取最大匹配数。 #include<bits/stdc++.h> using namespace std; const int N=1e5+10; int n,m,k; int match[
阅读全文

浙公网安备 33010602011771号