题意 Sunke 有一棵 \(N + 1\) 个点的树,其中 \(0\) 为根,每个点上有 \(0\) 或 \(1\) 个石子, Sunke 会不停的进行如下操作直至整棵树没有石子 : 把 \(0\) 上面的石子从树上拿走放入口袋 ; 把每个点上的石子移到其父亲上 ; 对于每个点 , 若其石子数 \(≥ 2\) , 则移除该点所有石子(不放入口袋). 求对于所有 \(2^{N+1}​\) 种放置石子的方案 , 最终 Snuke 口袋中石子数是多少 , 对 \(10^9+7​\) 取模 . \((…
题目链接 BZOJ4919 题解 链上的\(LIS\)维护一个数组\(f[i]\)表示长度为\(i\)的\(LIS\)最小的结尾大小 我们可以用\(multiset\)来维护这个数组,子树互不影响,启发式合并 一个点取更新数组时,只会改变第一个比它大的地方,因为这个点一定是将比它小的位置\(+1\),只有\(+1\)后位置的值比它大才会产生贡献 所以找到第一个大于等于当前节点权值的位置,改为当前节点权值即可 复杂度\(O(nlog^2n)\) #include<algorithm> #incl…
好强的题. 方案不好算,改成算概率,注意因为是模意义下的概率所以直接乘法逆元就好不要傻傻地开double. 设$f[i][d][0]$为第i个节点离d层的球球走到第i个点时第i个点没有球的概率, $f[i][d][1]$为有1个球的概率, $f[i][d][2]$为有2个球及以上的概率. 我们可以把$f[i]$看成一个队列, 然后从儿子转移的时候, 就是把儿子的队列一个一个合并起来,最后在队列头加上一个$f[i][0]$, 并且把队列里的所有$f[i][0$~$d][2]$加上$f[i][0$~…
Description Solution 神仙操作orz. 首先看数据范围,显然不可能是O(n2)的.(即绝对不是枚举那么简单的),我们考虑dp. 定义f(x,k)为以x为根的子树中与x距离为k的节点数:g(x,k)为在以x为根的子树中选择两个点,使得另一个点应在x子树外且离x距离为k的方案数(或者距离为0).但是这样子暴力转移怕是会崩em,考虑优化. 这里的树是棵静态树,考虑树链剖分,点分治之类的思想. 最后,由于很多时候它的复杂度和树的高度有关,考虑长链剖分. 转移的话,暴力枚举所有轻链(啊…
题目链接 https://atcoder.jp/contests/agc007/tasks/agc007_e 题解 首先有个很朴素的想法是,二分答案\(mid\)后使用可行性DP, 设\(dp[u][x][y]\)表示\(u\)子树内是否可以找到一条路径,在经过第一个叶子前路程是\(x\), 经过最后一个叶子前路程是\(y\). 这个DP显然做了很多无用功,比如我们发现完全可以只记录true的状态\((x,y)\),进一步发现如果合法状态\((x,y)\)存在另一合法状态\((x',y')\)满…
LINK:Druzyny 这题研究了一下午 终于搞懂了. \(n^2\)的dp很容易得到. 考虑优化.又有大于的限制又有小于的限制这个非常难处理. 不过可以得到在限制人数上界的情况下能转移到的最远端点 且这个数组是单调的. 而下界是随意的. 这个可以利用单调队列做 也可以暴力线段树. 然后考虑怎么优化 考虑CDQ分治 不过这里算是基于时间的分治吧. 大体上就是求出来左边让左边对右边进行贡献. 考虑这部分怎么做 左边为 \([l,mid]\)右边为\(mid+1,r\) 分别设两个决策\(j,i\…
Codeforces 题面传送门 & 洛谷题面传送门 首先这个 if 与 end 配对的结构显然形成一个树形结构,考虑把这棵树建出来,于是这个程序的结构就变为,对树进行一遍 DFS,到达某个节点时,按照顺序遍历其所有儿子,如果儿子是叶子节点则执行赋值操作,否则进入到对应子树中执行相应操作,如果一个节点所有儿子对应的操作都被执行了就回溯,不难发现该过程与原程序等价. 考虑树形 dp.可以发现对于一棵非叶节点,在首次进入这棵子树时,程序中 \(x\) 的值已经确定了--就是 if v 中 \(v\)…
题面 题目背景 因为出题人天天被 ZZH(Zou ZHen) 吊打,所以这场比赛的题目中出现了 ZZH . 简要题面 数据范围 题解 (笔者写两个log的平衡树和启发式合并卡过的,不足为奇) 首先,很容易看出来n^2的做法是个树形DP,而且不是换根DP(笔者想换根DP想了半小时,发现题读难了,唉), 设 dp[i] 为从 i 出发的答案,容易想到这样的状态转移: (depth是从1到每个点的距离,即深度,ancestors是每个点的祖先集) 怎么办,j 好像要在 i 的子树中枚举? 但是这个式子…
传送门 注意到一种颜色改了之后就不能改回去了. 因此可以启发式合并. 每次把小的合并给大的. 这样每个数最多被合并logloglog次. 如果维护一棵比较下标的平衡树的话,对于答案有贡献的就是每个数与前驱和后继的差值. 于是就用setsetset实现啦. 代码: #include<bits/stdc++.h> #define N 100005 using namespace std; inline int read(){ int ans=0; char ch=getchar(); while(…
题面 思路 我们首先考虑传统的链上LIS做法:保存每个长度的LIS末端的最小值,二分查找 那么这道题其实就只是搬到树上来做了而已 我们考虑一个节点,假设它的儿子已经处理完毕了 那么我们选择LIS最长的儿子进行继承,然后每次和其它儿子合并 合并的方法就是逐位取min值 合并完了以后再把当前节点二分一下加进去 记录的LIS,因为本题中的路径可以往根走也可以往叶子走,所以我们要记录从根开始的LIS和从叶子开始的LIS(其实就是从根开始的LDS),维护方法是一样的 然后对于答案的统计,有三种情况: 以当…