题意:给定 $n$ 个括号序,让你从中选取一些括号序按照任意顺序拼接,最终生成一个合法的括号序列,求这个合法序列长度最大值. 题解:假设括号序列相对顺序固定,而我们要做的只是判断选还是不选的话可以转化为一个简单的背包问题: 令 $f[i][j]$ 表示考虑前 $i$ 个括号序,左括号比右括号多 $j$ 个的最长长度. 转移为:$f[i][j]=max(f[i][j],f[i-1][j-k]+len[i])$ 其中 $k$ 表示当前序列 $i$ 中右括号比左括号多的个数. 转移的时候让 $j>=0…
目录 @description@ @solution@ @accepted code@ @details@ @description@ 卡常数被称为计算机算法竞赛之中最神奇的一类数字,主要特点集中于令人捉摸不透,有时候会让水平很高的选手迷之超时. 普遍认为卡常数是埃及人Qa'a及后人发现的常数.也可认为是卡普雷卡尔(Kaprekar)常数的别称.主要用于求解括号序列问题. 据考证,卡(Qa'a)是古埃及第一王朝的最后一位法老.他发现并研究了一种常数,后世以他的名字叫做卡常数.卡特兰数的起源也是因…
4919: [Lydsy1706月赛]大根堆 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 599  Solved: 260[Submit][Status][Discuss] Description 给定一棵n个节点的有根树,编号依次为1到n,其中1号点为根节点.每个点有一个权值v_i. 你需要将这棵树转化成一个大根堆.确切地说,你需要选择尽可能多的节点,满足大根堆的性质:对于任意两个点i,j,如果i在树上是j的祖先,那么v_i>v_j. 请计算…
传送门 因为区间 gcd 的变换不会超过 log 个,所以我们可以暴力枚举区间起点,复杂度是 n*logn 的 #include <bits/stdc++.h> using namespace std; #define rep(i,a,b) for(int i=a;i<=b;++i) #define fd(i,a,b) for(int i=a;i>=b;--i) ,mod=; template <typename T> bool check_Max(T &x,…
这个和 bzoj 5469 几乎是同一道题,但是这里给出另一种做法. 你发现你要求的是一个树上 LIS,而序列上的 LIS 有一个特别神奇的 $O(n\log n) $ 做法. 就是维护一个单调递增的栈,如果发现新加元素大于栈顶,则直接加入,否则在序列中二分出一个大于等于该元素的最小值,然后替换掉. 这个单调栈维护的并不是 LIS,而是 LIS 中每个长度的最小结尾数值. 这个拓展到树上同理,你发现儿子之间互不影响,所以可以直接合并. 然后,再用当前节点的值去替换一个大于等于这个值的最小值. c…
题目链接 考虑树退化为链的情况,就是求一个最长(严格)上升子序列. 对于树,不同子树间是互不影响的.仿照序列上的LIS,对每个点x维护一个状态集合,即合并其子节点后的集合,然后用val[x]替换掉第一个大于它的数(有等于的就不换了). 最后根节点状态集合的大小就是答案了. 关于替换数,可以先找到这个数的位置,如果有这个数就不用管了:没有的话插入进去,然后递归回去,找到一个靠右的位置删掉. 当然其实不用线段树合并这么麻烦,直接上multiset启发式合并就可以了.. 注意是合并了子树的状态,so叶…
传送门 势能分析平衡树,splay或treap都可以 放个指针版的就跑 #include <bits/stdc++.h> using namespace std; #define rep(i,a,b) for(int i=a;i<=b;++i) ; template <class T> inline bool check_Max(T &x, const T&y) { return x<y?x=y,false:true;} template <cla…
我不会告诉你这是线段树合并的好题的... 好吧我们可以搞一个multiset在dfs时求出LIS(自带二分+排序)进行启发式合并,轻松加愉悦... #include<cstdio> #include<iostream> #include<set> ; #define R register int using namespace std; inline int g() { R ret=; register char ch; while(!isdigit(ch=getcha…
F[x][i]表示x的子树中取的数字<=i的最大值,线段树合并优化DP 写得很难看,并不知道好看的写法 #include<cstdio> #include<algorithm> using namespace std; int cnt,n,Num,ans,last[200005],tag[10000005],ls[10000005],rs[13000005],E[200005],a[200005],Fa[200005],root[200005],ANS[200005],tre…
[题解] 求一个序列的LIS有一个二分做法是这样的:f[i]表示长度为i的上升序列中最后一个数最小可以是多少,每次二分大于等于当前数字x的f[j],把f[j]修改为x:如果找不到这样的f[j],那就把长度加一并记录新的f(即f[++len]=x) 现在我们把这个做法放到树上,同样是可以做的.我们用set维护子树内的f数组,父节点在其孩子合并得到的set中二分第一个大于等于它的数字,换成父节点自己的值.合并子树的set直接启发式合并即可.两个log的复杂度. #include<cstdio> #…