07 2017 档案
摘要:floyde+bitset 可以用tarjan+递推,复杂度n+m 但是我们也可以用传递闭包+bitset,复杂度n^3/32 就是通常floyde是k=1->n i=1->n j=1->n f[i][j] |= f[i][k] * f[k][j]但是我们发现floyde的两维数组可以用bitset
阅读全文
摘要:AC自动机+trie图优化 很明显就是要一个串不能匹配到任何一个病毒,那么我们就建一个AC自动机 不能匹配的话也就是一个节点不能是单词结束节点,fail指针也不能是结束节点 然后就卡壳了。。。zz 我们把自动机建成trie图,也就是不存在的节点直接指向原来fail指针,然后我们只要在这个图上找有没有
阅读全文
摘要:树链剖分+离线 思路很好 看见这种题肯定知道不能直接求,就得在lca上搞事情 将询问拆成两个,排序,然后离线不断从i=1-n到根的路径上全部+1,每次询问就询问从z到根的路径和 我们想一想,就可以知道z和i,将i到根的路径全部+1,那么lca的深度就是z到根的权值和,而且这个权值和满足可加性,那么我
阅读全文
摘要:dfs序 dfs序真神奇 dfs求出入栈时刻和出栈时刻,然后在in和out分别打上1和-1就能统计路径和了。 其实这里dfs序能够让我们求一个点处于哪些节点的子树内,而一个节点只处于从自己到跟路径的节点的。 这里的dfs序有些像括号序列,如果一个点不在另一个点的子树内,那么也就不在另一个点的括号内,
阅读全文
摘要:线段树 这题真是无聊 把式子拆开,然后可知维护xi,yi,xi^2,xi*yi,重点在于标记下传,当我们进行2号操作时,直接累加进答案和标记即可,进行3号操作时,update时先把自己这层赋值成要改变的值,再清空这层2号标记,每次pushdown把这层的下一层的标记清空,因为下一层被覆盖了,push
阅读全文
摘要:ac自动机+bit 很早以前就做过这道题了,再做一遍。 构建ac自动机的话就是模拟一下就可以了,然后就是如何统计答案。 这里巧妙地利用了fail树的性质,fail树是指当前在trie上从根到这个节点的路径,也就是某个单词的前缀,这个单词的前缀的后缀能够匹配上另一个单词的前缀,于是就把fail指针连向
阅读全文
摘要:期望dp 首先如果k=n的话,那么我们从后往前,只要看到两者的灯就关上,因为如果当前一个灯没关上,那么之后不可能关上,一个灯只能由自己倍数控制,所以这样我们就计算出了需要操作的次数,如果这个次数<=k,直接把这个步数乘上阶乘就可以了。 考虑期望的部分,设f[i]为当前状态下还需要操作i次结束的期望步
阅读全文
摘要:状压dp 预处理每个状态的初始值,枚举子集就行了 #include<bits/stdc++.h> using namespace std; const int N = 18, inf = 1000000010; int W, n; int t[N], w[N], sumw[1 << N], sumt
阅读全文
摘要:cdq分治+dp 看见三维偏序是cdq,互相包含是最长上升子序列 这个代码是错的 交了两份代码,发现手动出数据是不一样的。。。 不调了 #include<bits/stdc++.h> using namespace std; typedef long long ll; const int N = 5
阅读全文
摘要:决策单调性+整体二分 这里就是j<k且kj劣于j,j不会再选,所以我们整体二分 pos是因为从L->R中这个是最优点,所以对于mid+1->r选pos之前肯定不优,l->mid-1不会选>pos,因为每个位置都小于mid,并且pos->mid-1这段区间的决策点没有pos优,因为当前f[i]的i小于
阅读全文
摘要:扫描线 想法挺妙 搞了很长很长时间。。。 http://www.cppblog.com/superlong/archive/2010/08/06/122427.html #include<bits/stdc++.h> using namespace std; typedef long long ll
阅读全文
摘要:cdq分治+单调栈+二分 对y分治,单调栈上部维护递增,下部递减,因为一旦一个点不满足单调性了,就会把前面的点卡掉,所以在单调栈里干掉那些点 #include<bits/stdc++.h> using namespace std; typedef long long ll; const int N
阅读全文
摘要:树状数组+离线 按x排序,y离散化,树状数组查询,跟逆序对一样 #include<bits/stdc++.h> using namespace std; const int N = 500010; int n, m, tot, lim; vector<int> v; int ans[N], aa[N
阅读全文
摘要:A 出题人不给样例解释。。。具体程序 #include<bits/stdc++.h> using namespace std; int n; char s[100]; int main() { scanf("%d%s", &n, s + 1); int ans = 0, tot = 0; for(i
阅读全文
摘要:后缀数组+二分 中间加个字符,然后二分判断即可 #include<bits/stdc++.h> using namespace std; typedef long long ll; const int N = 100010; int n, top, k, tot, m, ans; int a[N],
阅读全文
摘要:二分+后缀数组 并查集怎么做? 二分长度,然后扫描一遍,如果lcp比值大,那么肯定能满足这个x,因为lcp比x大说明包含长x的lcp #include<cstdio> #include<algorithm> using namespace std; typedef long long ll; con
阅读全文
摘要:后缀数组+单调栈 看了好长时间,最后看了张神的程序才搞懂 意思就是求所有子串*n*(n+1)/2 n是子串出现次数 事实上,lcp可以看成宽度为1,高度为lcp值的长方形,所有lcp放在一起就是一堆长方形放在一起,然后我们就要求对于每个高度对应的长方形的面积乘上一个值 每个长方形可以用单调栈求,也就
阅读全文
摘要:后缀数组+st表+单调栈 这道题是差异的加强版 看起来和差异差不多,但是询问的位置是不连续的,那么我们让他们连续就行。 把每个位置赋成rank值,因为lcp[i]表示rank=i和i+1的最长公共前缀,然后st表处理出相邻两个rank的lcp值,然后和差异一样,单调栈处理最左端和最右端的区间,乘起来
阅读全文
摘要:st表 我还不会st表 f[i][j]表示[i,i+2^j)区间的最值 构造就像lca一样f[i][j]=f[i][j-1] f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1]) 表示[i+2^(j-1)) [i+2^(j-1), i+2^j) 然后查询找出一个2的
阅读全文
摘要:区间dp dp[i][j]存i->j区间的所有取值 然后枚举分割点,枚举两个存的值,分别运算存储。 看见这种不确定分割顺序,两个区间合并的情况,就要用区间dp。 #include<bits/stdc++.h> using namespace std; const int N = 60; int n,
阅读全文
摘要:dp 没想出来 最先开始想 dp[i][j][k]表示s匹配到i,t匹配到j,当前分了k段的方案数 s[i]==t[j] dp[i][j][k]+=dp[i-1][j-1][k-1] s[i]==t[j]&&s[i-1]==t[j-1] dp[i][j][k]+=dp[i-1][j-1][k] dp
阅读全文
摘要:dp 以前做过 忘了。 想破脑袋不知道怎么设状态 dp[i][j][k]表示选到第i个硬币,当前和为j,能否弄出k dp[i][j][k]|=dp[i-1][j][k]|dp[i-1][j][k-c[i]]|dp[i-1][j-c[i]][k-c[i]] 如果发现状态不行,就试着多加一维,也许就能搞
阅读全文
摘要:A 暴力查询,分三段查就可以了 #include<bits/stdc++.h> using namespace std; const int N = 110; int n, pos; int a[N]; int main() { scanf("%d", &n); for(int i = 1; i <
阅读全文
摘要:dp dp[i][j]表示到了i赢和输的差为j 如果这位是?向dp[i-1][j-1],dp[i-1][j],dp[i-1][j+1]转移,如果是W向dp[i-1][j-1]转移,如果是L向dp[i-1][j+1]转移,如果是D向dp[i-1][j]转移 #include<bits/stdc++.h
阅读全文
摘要:费用流 并没有想出来构图方法 我们设立源汇,其实我们关心的是相邻两个值的差值,如果差值小于0说明需要长高,那么向汇点连边差值,说明需要修改,如果差大于零,那么由源点连边差值,说明可以提供修改空间,再由源点向1和n+1连边inf,因为这两个点是可以无限修改的。然后1-2-3-n+1连双向边,费用为1,
阅读全文
摘要:二分+2-sat 枚举第一个权值,二分第二个权值,然后2-sat检查,当第一个权值已经不能形成二分图时,再往下没意义,因为没法分成两个点集。(双指针好像跑得慢) #include<bits/stdc++.h> using namespace std; const int N = 410; struc
阅读全文
摘要:模拟 很明显应该尽量选最大或最小的数。那么我们维护一个set,再维护一个mp,每次检查是否能选,如果选完这个数上面的东西不悬空就可以选,每次选完都要更新四周-2+2的方块,因为再远就影响不到了 #include<bits/stdc++.h> using namespace std; typedef
阅读全文
摘要:贪心 感觉思路很奥妙 首先我们把那些比两边小的数删掉,因为不删的话两边的数就会选这个数,这样就成了先上升后下降的序列,很明显除了第一第二大的数都能选,然后统计就好了。 #include<bits/stdc++.h> using namespace std; typedef long long ll;
阅读全文
摘要:贪心 这个贪心不太懂啊 dfs返回子树需要的最小值,然后按需要减消耗排序,然后贪心选取即可。 #include<bits/stdc++.h> using namespace std; typedef pair<int, int> PII; const int N = 110; struct Node
阅读全文
摘要:费用流 这种棋盘模型大概都是网络流吧 首先我们知道棋子之间不会影响到达目标的步数,那么就好做了,枚举终点,然后就是最小权匹配了,因为就是寻找总和最小,然后费用流就行了。 #include<bits/stdc++.h> using namespace std; const int N = 110, i
阅读全文
摘要:哈夫曼树+搜索 抄了抄代码 先开始不知道怎么限制哈夫曼树,然后看了看代码,是用bfs序来限制。因为每个节点的右子树节点肯定不小于左儿子,同一层也是。所以先搞出bfs序,然后搜索,判断每一层右边是否大于左边。 哈夫曼树的每个节点必然会有零个或两个儿子,这也是判断无解或有解的情况。 #include<b
阅读全文
摘要:最短路 吐槽一下。。。最先开始写了个地图哈希,6kb,然后不是正解,又写了个spfa,4kb,还是不对,无奈抄标程,结果把spfa改成dijiestra就对了。。。 由于只有两个变量,所以我们设一个四维状态,d[x0][y0][x1][y1],然后就可以跑最短路了。如果是多维的话就得用哈希了。 但是
阅读全文
摘要:状压dp+凸包 并没有看出来凸包的性质 首先答案一定在凸包上,然后每个凸包的角加起来是一个圆,那么就相当于凸包周长加一个圆了。然后预处理,再状压dp计算即可。
阅读全文
摘要:分类 首先我们要对询问分类,如果相差log级别就第一种询问,否则第二种。 第一种直接暴力lower_bound,复杂度玄学 第二种归并,复杂度玄学 但是就是过了。感觉很容易卡。 #include<bits/stdc++.h> using namespace std; const int N = 40
阅读全文
摘要:二分+高斯消元 我们利用物理里的势能来表示,每个点有一个势能h,再由流量守恒可以得到deg[x]*h[x]=sigma(h[y]) 如果x,y之间有边。这个式子是由流量守恒推出的,所以当x=1或n是不满足这个方程的。 每次二分n的势能,然后把1和n赋值,高斯消元,检验答案。 势能保证了到达一个点所有
阅读全文
摘要:dp+优化 很明显可以用单调队列优化。 记录下自己犯的sb错误: 数组开小,sum没搞清。。。 #include<cstdio> #include<cstring> using namespace std; const int N = 110, M = 10010; int n, m, k, ans
阅读全文
摘要:扫描线+dp 先对坐标排序,然后·用set维护端点,每次插入左端点,扫描到右端点时删除。每次考虑新插入时分割了哪两个木板,自己分别连边,再删除原来的边,最后dp(好像得维护used,有环) #include<bits/stdc++.h> using namespace std; typedef pa
阅读全文
摘要:线性基+dfs树 我们先搞出dfs树,其实最终路径就是最初的路径和一些环异或。 环最多只有m-n+1,因为一共有m条边,然后有n-1条边在dfs树上,所以还剩m-n+1条边,都可以构成环。 所以dfs搞出环,线性基找最大值就可以了。 #include<bits/stdc++.h> using nam
阅读全文
摘要:trie+堆 跟超级钢琴是一个想法 我们先把每个数插进trie里,然后对于每个数查找异或第二小,因为第一小肯定是和自己。 然后就和超级钢琴一样,从堆里取出,插入第k+1小。trie是可以查找第k小的,只要维护一个size。 #include<bits/stdc++.h> using namespac
阅读全文
摘要:LCT维护MST+子树信息 看了好长时间题解 editorial 结论:像做最小生成树一样,当每个连通块都是偶数个点就停下来。 每次复杂度mlogm 口胡 首先我们发现奇数个点是不满足每个点度数为奇数,因为一条边贡献两个度数,所以度数一定是偶数,但是奇数个点每个点奇数度度数总和是奇数,所以点数一定是
阅读全文