08 2019 档案
摘要:对于每一个节点,我们只需要知道他上len次插入(len是这个队列的元素个数)时所插入的元素就可以了 那么只需要将所有插入建为一棵树,然后找len次祖先就可以了,这个用倍增维护即可 还有一种比较神奇的做法,详见loj讨论(是我太菜了吧) 1 #include<bits/stdc++.h> 2 usin
阅读全文
摘要:考虑二分求LIS的过程,就是维护一个序列,其中第i个数表示长度为i的最小结尾,而插入操作就是查找第一个大于x的位置并替换掉 用线段树维护,二分的过程也可以用线段树来完成,对线段树可持久化即可 1 #include<bits/stdc++.h> 2 using namespace std; 3 #de
阅读全文
摘要:用f[i]表示以i这个值为结尾的最长上升子序列,考虑插入所产生的影响:1.因为插入顺序从小到大,因此不会改变现有的f值2.这个点f值就是所有位置在他之前的f取max再+1,而因为序列要支持插入操作,需要使用平衡树来维护 1 #include<bits/stdc++.h> 2 using namesp
阅读全文
摘要:首先要知道一个式子:$\mu(lcm(i,j))=\mu(i)\cdot \mu(j)\cdot \mu(gcd(i,j))$(分是否为0讨论)令$d=gcd(i,j)$,$n'=\lfloor n/d \rfloor$,$m'=\lfloor m/d \rfloor$$\sum \mu(lcm(i
阅读全文
摘要:首先计算出以1为左端点的所有区间的mex,考虑删除左端点仍然维护这个序列:设当前删除点下一次出现在y,y~n的mex不变,从左端点到y的点中大于删除值的点要变成删除值,因为这个是不断递增的,所以是一段区间,可以用线段树来维护。 1 #include<bits/stdc++.h> 2 using na
阅读全文
摘要:定义状态f[i][j][k][x]表示有多少个i位数t有j位大于x,k位等于x,然而复杂度无法接受,发现可以改变状态为f[i][j][x]表示前i为有j个数字大于等于x的方案数,就可以快速转移了 1 #include<bits/stdc++.h> 2 using namespace std; 3 #
阅读全文
摘要:分块,可以发现众数一定是整块的众数或在不整块中出现的数,预处理出f[i][j]表示第i块到第j块的众数,然后对于询问暴力枚举所有散块的数,相当于要支持查询一个数在一个区间内出现的次数,可以用可持久化权值线段树,也可以直接对每一个数开一个vector记录位置二分(离散),时间复杂度是$o(nKlog_
阅读全文
摘要:首先算出两个区间包含的答案,然后就可以删掉所有被包含的区间,此时发现右端点也单调递增那么对于任意一种方案,假设他选择了区间[l,r]中的某一些区间且选择了l和r,那么一定可以等价为仅选择l和r两个区间,因此答案一定是选某两个区间简单计算后可以发现答案有单调性,所以用优先队列来找到上一个最大值即可另外
阅读全文
摘要:基本思路是,要让所有黑点都相对应(所以首先判断黑点的个数)。如果没有交换限制,可以按以下方法建图:源点向所有初始黑点连(1,0)的边,最终黑点向汇点连(1,0)的边,相邻的两点连边(inf,1),最小费用最大流即可。考虑限制,我们把交换分为两种:(将1)交换进来/交换出去,因此需要两条边(三个点)来
阅读全文
摘要:可以发现k条白边的最小生成树可以用:1.求出黑边的最小生成树;2.贪心选择[白边-对应环上最大的黑边]最小的加入;3.重复2操作k次考虑如何模拟这个过程,由于每一次贪心的代价是单调递增的,所以可以二分确定最后一次代价mid,即每一次贪心都有白边-替换边<=mid如果将所有白边边权减去mid(记为白边
阅读全文
摘要:考虑没有爆发,那么相当于是带权最小不可交路径覆盖,由于只能从编号小的到编号大的,因此一定是DAG,而DAG的最小路径覆盖可以拆点并跑最大流,那么带权的只需要跑费用流即可(S向i连(1,0)的边,i’向T连(1,0)的边,i向j’连(1,t)的边,其中i->j有时间为t的边)。考虑爆发操作,相当于让任
阅读全文
摘要:发现5个点的联通情况仅52种,因此状压:令f[i][j]表示前i个点满足:1.前i-k个点是树;2.最后k个点连通性为j的方案数;3.最后k个点到前i-k个点有边,转移用矩阵乘法:暴力求出A[i][j]表示(连通性)从状态i转移到j的方案数,快速幂一下即可。 1 #include<bits/stdc
阅读全文
摘要:根据$2^b$分组,组内处理出g[i][j]表示当容量为$j\cdot 2^{i}$且只能选b=i时最大价值,再组间dp用f[i][j]表示当容量为$j\cdot 2^{i}+(w\&(2^{i}-1))$且只能选$b<=i$时的最大价值(j的范围只有$\sum_{i=1}^{n}ai$,即使所有b
阅读全文
摘要:记源点为S,汇点为T,第i天裂成两个点,分别是i1和i2,表示剩余的毛巾(都是脏毛巾,因为一定可以做到每天不剩余干净的毛巾)和使用的毛巾(用来保证最大流符合条件),然后考虑以下边:1.S向每一个i1连一条(ni,0)的边,表示用过的毛巾;2.i2向每一个T连一条(ni,0)的边,表示消耗毛巾;3.每
阅读全文
摘要:首先,源点向每一个车主连(1,0)的边,然后把每一个工人拆成n个点,第i个点表示修倒数第i辆车,那么这辆车对答案的代价就是time*i(time表示这辆车的时间,i表示倒数第i辆),就是说每一个车主向nm个工人的点连(1,time*i)的边。最后,每一个工人的点向汇点连(1,0)的边即可。 1 #i
阅读全文
摘要:不断删除重边,然后将两个点的边集启发式合并(要考虑到两棵树),合并时发现重边就加入队列,最后判断是否全部删完即可 1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 100005 4 set<int>s[N]; 5 map<int
阅读全文
摘要:分块,对于sqrt(n)以内的点用二进制优化多重背包+前缀和来做,处理出f[i][j]表示前i种权值为j的方案数对于sqrt(n)以外的点有两个性质:1.与数量无关且数量不超过sqrt(n);2.权值相邻;3.那么一定可以用两种操作来构造出来权值序列:1.加入一个sqrt(n)+1;2.将现有数+1
阅读全文
摘要:设f[i][j]表示第i个点在第j个时间从1到达的最晚出发时间,有转移方程$f[i][j]=max(f[to][x])(j\ge y)$,然而显然不能暴力转移。但通过这个可以发现f[i][j]的答案与j的大小没有直接关系,而是与能走哪些边有关。于是,将询问和每一个点边的y排序后,发现一条边如果之前搜
阅读全文
摘要:点分治,当一个节点作为重心时,统计出:1.每一个点的深度;2.每一个点所能选择的路径对应点区间,可以发现这样的点数只需要nlogn。然后类似于bzoj2006超级钢琴的堆+线段树来做即可。 1 #include<bits/stdc++.h> 2 using namespace std; 3 #def
阅读全文
摘要:发现是链上的问题,所以树链剖分发现要查询第k大,因为第k大不支持合并,所以要二分答案二分答案后相当于询问一些区间内大于某数的数个数,直接线段树套平衡树即可时间复杂度$o(nlog^{4}_n)$(跟$o(n^{2})$有什么区别)可以卡过 1 #include<bits/stdc++.h> 2 us
阅读全文
摘要:可以发现一定只会填以某个字符为中心的最长回文串,然后用hash+二分/manacher求出以i为中心的最大的长度(即所有可能会填的回文串,共n个),将这些回文串根据左端点排序后贪心选择在当前位置之前最远的结束位置即可 1 #include<bits/stdc++.h> 2 using namespa
阅读全文
摘要:考虑点分治,将询问离线后计算重心到每一个点的线性基,然后再询问重心到每一个点的线性基,时间复杂度为$o(3600q)$,可以过(然而太菜的我写了倍增维护线性基,震惊于倍增和线性基常数之小) 1 #include<bits/stdc++.h> 2 using namespace std; 3 #def
阅读全文
摘要:任选一条路径,考虑如果从一个点向另外一个方向走,该方向上一定有一个环(否则来去无意义),所以相当于一条路径+许多的环异或最大值,可以用线性基来求 1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 100005 4 #define
阅读全文
摘要:先求出最小生成树,然后维护f1/f2[i][j]表示i到$2^{j}-1$祖先中最大和严格次大边,枚举生成树外的每一条边并查询这条边两点间的最大边和严格次大边,若最大边<插入边,就用插入边替换最大边计算答案,否则用插入边替换次大边计算答案 1 #include<bits/stdc++.h> 2 us
阅读全文
摘要:考虑LIS的一种求法:维护每一个长度的最小结尾,此时这个序列只与每一个数字有没有出现有关,用2^10状压,状压+数位dp即可 1 #include<bits/stdc++.h> 2 using namespace std; 3 #define ll long long 4 int t,k,a[21]
阅读全文
摘要:首先将问题转化为2x^x=3x,那么相当于让x右移一位和原数的1不相交,即不含有相邻的1,第一个问题可以直接数位dp,第二个问题可以类似dp+矩乘优化即可 1 #include<bits/stdc++.h> 2 using namespace std; 3 #define ll long long
阅读全文
摘要:首先有暴力dp,令f[i][j][k]表示A中前i个与B中前j个分成k段的方案数,有$f[i][j][k]=\sum_{l=1}^{i}f[i-1][j-l][k-1](A[i-l+1,i]=B[j-l+1,j])$,显然这样时空复杂度都无法承受。进而考虑优化:l的取值一定是0<l<t,那么只要用前
阅读全文
摘要:首先二分枚举答案t,考虑删去的边应满足的条件——所有大于t的链全部经过且长度不小于最长链-t,第二个条件很好判断,考虑第一个条件。 先考虑有祖先-后代关系的链,用如果把这条链到1看成一个序列,那么差分一下再dfs一遍就可以对这条链上每一个点打上标记。 然后没有祖先-后代关系的链,同样可以分解成两条链
阅读全文
摘要:首先,我们肯定要用到二分答案。 这道题目就是统计第k个μ不是0的数,线性筛显然会炸飞的,但当二分出一个数而统计有多少个小于等于他的合法数时,就可以容斥一下,即:1^2的倍数都不合法,2^2的倍数都不合法……4^2的倍数已经通过2^2统计过且没有重复……6^2的倍数被3^2的倍数和2^2的倍数重复统计
阅读全文
摘要:定义dp[i]表示当前连通块状态为i的方案数(状态记录该状态每一个连通块的大小),那么从小到大枚举每条边,考虑这条边在不在最小生成树上: 1. 如果不在最小生成树上,那么这条边有$\sum_{i=1}^{scc}\sum_{j=i+1}^{scc}Si\cdot Sj$(Si表示第i个连通块的点数)
阅读全文
摘要:先解释一下checker.cpp,它的判定标准是2e7,即答案超过2e7就认为代价过大了。 首先,很容易想到的办法是直接对其快排,从外到内交换区间即可,然而这样会被邪恶的出题人给卡掉(当然其实随便一组大数据都能卡)。 由于一次操作可以翻转而不仅仅是交换,所以要将一个区间分成两块仅仅需要经左右两个区间
阅读全文
摘要:1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 2000005 4 long long n,ans,f[N],vis[N],p[N]; 5 void mobies(int n){ 6 f[1]=1; 7 for(int i=2
阅读全文
摘要:1 #include<bits/stdc++.h> 2 using namespace std; 3 #define ll long long 4 ll n,ans; 5 ll phi(ll n){ 6 ll ans=n; 7 for(ll i=2;i*i<=n;i++){ 8 if (n%i==0
阅读全文
摘要:建立线段树,维护区间左端点选/不选,右端点选/不选且不含有相邻两个同时选的最大值,合并时注意细节即可 1 #include<bits/stdc++.h> 2 using namespace std; 3 #define mid (l+r>>1) 4 #define L (k<<1) 5 #defin
阅读全文
摘要:结论:最短路径一定是单独的一条边且在最小生成树上,可以用反证法证明。那么求出最小生成树,对于每一个点建立一棵权值线段树,再对每一个权值线段树上的叶子节点开一个multiset,维护所有儿子中该种颜色的权值(普通节点仍维护区间最小值),答案也需要用multiset维护。 1 #include<bits
阅读全文
摘要:题目要求其实相当于要让大于和小于m的数的个数都不超过n/2,因此当要对一个数处理时,要么把它改成m,要么不作修改,根据这个贪心就可以完成了。 1 #include<bits/stdc++.h> 2 using namespace std; 3 #define ll long long 4 ll n,
阅读全文
摘要:分割实际上就是不断地从两端取出一样的一段,并对剩下的串进行分割。下面我们来证明一下每一次贪心取出最短一段的正确性: 考虑两种分割方式,分别表示成S=A+B+A和S=C+D+C,其中A就是最短的一段,那么当2|A|<|C|,显然就有C=A+E+A,那么就可以用三次划分来完成C,而当|A|<|C|<2|
阅读全文
摘要:记第i个位置有三个属性:1.ai表示原来的值;2.bi表示变成最大的值;3.ci表示变成最小的值。那么对于如果i在j的前面,那么必然有:$ai\le cj$且$bi\le aj$,那么令f[i]表示以i为结尾的最长上升子序列,即对求max(f[j])满足j能在i的前面,用树套树维护即可 1 #inc
阅读全文
摘要:用线段数维护一段区间内的两个信息:1.需要多少经验就可以让有一个人升级,2.等级和。单点修改直接暴力做就可以,区间修改考虑如果这个区间不会产生升级就不递归下去而是打上懒标记。 考虑这个算法的时间复杂度:单点修改的时间复杂度为$o(log_{2}n)$,而区间修改由于每一个点最多升级n+q次,总时间复
阅读全文
摘要:直接统计答案,令dp[i][j]表示前i个数最长的颜色各不相同后缀长度为j的方案数,如果一直令j<m,那么就相当于统计了方案数。 如何推出dp[i][j]呢?考虑i-1的最长前缀是多少:当小于j-1或等于j时,显然无法拼接成j;当等于j-1时,第i个位置就有m-j+1种方案;当大于j时,第i个位置对
阅读全文
摘要:发现加边操作不好处理,因此考虑先加完所有边后删边。 删去一对边x到y,如果两者中有一个不翘课显然没有意义,那么如果都翘课了那么就对他们进行判断,如果无法翘课就继续搜下去。 这样的时间复杂度看上去似乎是o(nm)的,但注意到每一个点最多由翘课变为不翘课一次,因此是o(n+m)的。 1 #include
阅读全文
摘要:小w喜欢的图可以发现就是一棵森林(是不是很神奇,其实易证:如果有环那么环本身就不合法,如果没有环那么显然合法)。继续研究发现删边最小<=>选边最大<=>最大生成森林,kruskal跑一下即可。 1 #include<bits/stdc++.h> 2 using namespace std; 3 st
阅读全文
摘要:定义f[i][j]表示从(i,j)走到最后一行的期望,不断从下往上dp那么对于每一行都可以得到m个方程。 但由于这m个方程不是DAG,因此考虑用高斯消元,但时间复杂度不对。 观察方程可以发现如果不断将f[i][j]表示出f[i][j+1]并代入那么就可以计算出f[n][m],再不断反代出来即可。 1
阅读全文
摘要:考虑令$b_{i}=a_{i+1}-a_{i}$,那么1操作相当于对L加上K,对(L,R]区间加上D,对R+1减去K+(R-L)*D,然后询问区间和即可 1 #include<bits/stdc++.h> 2 using namespace std; 3 #define L (k<<1) 4 #de
阅读全文
摘要:考虑可持久化权值线段树,维护区间和那么发现满足条件的最多只有一个点,因此从若左区间有超过k个走左区间,右区间有走右区间,都没有就没答案 1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 500005 4 #define mid
阅读全文
摘要:考虑A中第i次出现的j字符,最终位置一定是在B中第i次出现的j字符的位置,然后即求逆序对数量,cdq/线段树即可 1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 1000005 4 #define L (k<<1) 5 #de
阅读全文
摘要:莫队,再用树状数组/线段树维护一下逆序对数即可 1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 50005 4 #define L (k<<1) 5 #define R (L+1) 6 #define mid (l+r>>1)
阅读全文
摘要:令ai=Hi/i,那么即求有多少ai满足对于任意0<j<i,都有aj<ai,可以理解为强制选择的LIS,以下简称LIS2。考虑分块,块内维护最大ai和块内的LIS2(具体的),然后不断枚举块并二分找到该块的LIS2中第一个大于曾经的max的值,并修改答案和max即可。还有一种线段树的做法,即维护区间
阅读全文
摘要:对Y分块,对于Y<K,每一次1操作暴力修改这个Y的最大值,时间复杂度o(K);对于Y>K,维护一颗权值线段树并查询大于iK且离iK最近的数,时间复杂度o(6000000/K)(还有一个log),大约取K=2000左右(可以不用权值线段树而用并查集维护,复杂度较低) 1 #include<bits/s
阅读全文
摘要:根据魔法值从大到小插入到线性基中,然后即输出线性基中的所有数之和 1 #include<bits/stdc++.h> 2 using namespace std; 3 #define ll long long 4 struct ji{ 5 ll id; 6 int k; 7 bool operato
阅读全文
摘要:一棵子树的每一个儿子相当于划分一个区间,同时这些区间一定要存在一个点连续(直接的儿子),因此每一棵树最多只有两个儿子存在子树,并且这两个儿子所分到的区间一定是该区间最左和最右两段,所以ans*=(son)!(没有儿子的点任意排列)*2(两棵子树可以选择最左和最右),注意根节点还有两种划分方式,但当n
阅读全文
摘要:线性基中的所有数一定能够造出所有异或的结果,同时一定只有一种方式(否则这两种方式异或起来为0),那么只需要考虑为了异或出X,每一位的线性基要不要选,若X的这一位是1,那么别的方案一定可以使得这一位是0,因此会增加$2^{剩下的线性基个数}$个比X小的数,否则不会增加还有重复数字,可以发现除了线性基外
阅读全文
摘要:一个点的贡献即$(x+1)^3-x^3=3x^{2}+3x+1$(x表示结尾的长度),由于期望的可加性,分别维护末尾序列长度平方的期望,长度的期望(不能一起维护,因为后者平方并不是前者),直接计算即可 1 #include<bits/stdc++.h> 2 using namespace std;
阅读全文
摘要:插一块板表示让这个数字+1,问题转化为对于长度为1~n的序列,插入r-l块板(首尾也可以插板,每个点板数不限),有多少种方案,即求$\sum_{i=1}^{n}c(r-l+i,r-l)$考虑该式,再补上一项c(r-l+1,r-l+1),原式=$\sum_{I=1}^{n}c(r-l+i,r-l)+c
阅读全文
摘要:很难考虑矩形覆盖的问题,但可以考虑每一个点被覆盖的概率/期望(把矩形分成九部分后容斥即可),sigma起来即答案 1 #include<bits/stdc++.h> 2 using namespace std; 3 int t,n,m,k; 4 long long s,sum; 5 double a
阅读全文
摘要:定义状态f[i][j]表示发现了i种bug在j台电脑上后期望多少天能结束,$f[i][j]=(ij\cdot f[i][j]+(n-i+1)j\cdot f[i+1][j]+i(m-j+1)\cdot f[i][j+1]+(n-i+1)(m-j+1)\cdot f[i+1][j+1])/(ns)+1
阅读全文
摘要:由于题目的证明可以发现$ans\ge 2m/n \ge n-1$,于是大胆猜测答案就是n-1若n是奇数,则将边分为n组,每组(n-1)/2,如果同组内边没有交点,那么只需要每一组边一个权值区间,从每一组边一定不可能走回那组边(因为会经过其他组的边),所以答案至多n-1若n是偶数,先对n-1的图边分类
阅读全文
摘要:令f[i][j]表示以i为根的子树中选择j个点颜色为黑色的最大收益,$f[i][j+t]=max(f[i][j]+f[son][t]+val(i->son)$,其中$val(i->son)=(k-t)*t+(sz[son]-t)*(n-k-sz[son]+t)$,时间复杂度为$\sum_{i=1}^
阅读全文
摘要:令g[i][j]表示覆盖了i的子树中距离i大于等于j的所有点,f[i][j]表示覆盖了i的子树和子树外距离i小于等于j的所有点,有递推式$f[i][j]=min(f[i][j]+g[son][j],f[son][j+1]+g[i][j+1]),g[i][j]+=g[son][j-1]$,特别的有g[
阅读全文