bzoj

[BZOJ 3625] [Codeforces 438E] 小朋友的二叉树 (DP+生成函数+多项式开根+多项式求逆)

倖福魔咒の 提交于 2019-12-01 20:04:58
[BZOJ 3625] [Codeforces 438E] 小朋友的二叉树 (DP+生成函数+多项式开根+多项式求逆) 题面 一棵二叉树的所有点的点权都是给定的集合中的一个数。 让你求出1到m中所有权值为i的二叉树的个数。 两棵树不同当且仅当树的形态不一样或者是树的某个点的点权不一样 分析 设 \(c(i)\) 表示数值i是否在集合中。 \(f(i)\) 表示权值为i的二叉树的个数。那么 \[f(n)=\sum_{i=1}^n c(i) \sum_{j=0}^{n-i} f(j)f(n-i-j)\] 其中 \(i\) 表示根节点的权值,那么左右子树的权值和为 \(n-i\) ,枚举左右子树分别的权值 \(j,n-i-j\) ,为 \(\sum_{j=0}^{n-i} f(j)f(n-i-j)\) 我们把式子化成卷积的形式,设 \(F,C\) 为 \(f,c\) 的生成函数 \(F(x)=F(x)^2C(x)+1\) 解函数方程,得: \[F(x)=\frac{1 \pm {\sqrt {1-4C(x)}} }{ 2C(x)}=\frac{2}{1 \mp \sqrt{1-4C(x)}}\] 如果符号取-,那么x=0时分母为0无意义。 因此 \(F(x)=\frac{2}{1+\sqrt{1-4C(x)}}\) 多项式开方和多项式求逆即可。 代码 #include<iostream>

[BZOJ 3771] Triple(FFT+容斥原理+生成函数)

夙愿已清 提交于 2019-12-01 19:57:25
[BZOJ 3771] Triple(FFT+生成函数) 题面 给出 n个物品,价值为别为 \(w_i\) 且各不相同,现在可以取1个、2个或3个,问每种价值和有几种情况? 分析 这种计数问题容易想到生成函数。 设生成函数 \(A(x)=\sum_{i=1}^{n} x^{w_i}\) ,指数为价值,系数为选的方案数。A表示每种物品取1个的方案数。同理,我们可以写出每种物品取2个和3个的生成函数。 \(B(x)=\sum_{i=1}^{n} x^{2w_i}\) \(C(x)=\sum_{i=1}^{n} x^{3w_i}\) 然后就开始大力容斥. 取3个不同物品的情况 直接取3个物品的方案数为 \(A^3(x)\) ,但是我们还需要减去重复的,如 \((a,a,b),(a,b,a)\) 就算同一种情况。选2个物品 \(a\) 的方案为 \(B(x)\) ,再选一个物品 \(b\) 的方案为 \(A(x)\) ,任意排列有3种。因此要减 \(3A(x)B(x)\) 然而每种物品取3个 \((a,a,a)\) 这样的方案会被减去3次,而实际上只需要减去1次,所以还要加回 \(2C(x)\) 注意到 \((a,b,c)\) 的6种不同排列方案只算一次。总答案为 \[\frac{A^3(x)-3A(x)B(x)+2C(x)}{6}\] 取2个不同物品的情况 直接取3个物品的方案为 \(A

BZOJ 4199 品酒大会

浪子不回头ぞ 提交于 2019-11-30 23:34:14
BZOJ 4199 品酒大会 题意: 给定一个长度为 n n的串。 n ≤ 3 × 10 5 n≤3×105 对于 ∀ i ∈ [ 0 , n − 1 ] ∀i∈[0,n−1],求出 L C P ( s u f ( k ) , s u f ( j ) ) == i LCP(suf(k),suf(j))==i的数量并且求出其最大的权值积。 https://www.lydsy.com/JudgeOnline/problem.php?id=4199 Sol: 单调栈求出每个 H e i g h t [ i ] Height[i]能延伸的范围,然后乘起来,注意 H e i g h t [ i ] = 0 Height[i]=0时不能这么求 原因是会有多个 0 0,每个 0 0都会控制最小左边界和最大右边界,也就是说会算多次但是不对。 第二问直接 S T ST表然后对于每个点 i i求左右的最大最小然后匹配一下 数据比较弱,明显都没卡对于一个 i i,这个 i i是划分到左区间还是划分到右区间。 upd : 并查集做法好像 快很多的样子,好像也很好写 M e r g e Merge 有点烦 #include<cctype> #include<cstdio> #include<cstring> #include<algorithm> #include<algorithm> const int

BZOJ 4207 Can

青春壹個敷衍的年華 提交于 2019-11-30 19:48:28
题意: 因为是权贵提,就多挂了几个链接。 https://bzoj.zcmimi.tk/p/4207.html https://www.lydsy.com/JudgeOnline/problemset.php Sol: 要求最长? 看起来不太好做,不过d和k很小,于是考虑暴力。 找子区间要想分治吧,考虑当前分治中心为MID(强制跨过MID) 然后暴力往两边扩展,加个最优性剪枝就过了。 复杂度$O(Tn\log n\times d^k\times 2^k)$ #include<cstdio> #include<cstring> #define R register const int N = 1e5+7; int A[6][N], vis[N*10], n, d, k, ansl, ansr; inline int check(int omg) { for (int i = 1; i <= d; i++) if (vis[A[i][omg]]) return 1; return 0; } void dfs(int l, int r, int lx, int rx, int K) { while (check(l - 1) && l > lx) l--; while (check(r + 1) && r < rx) r++; if (r - l > ansr - ansl) ansl

【BZOJ】P2448 挖油

陌路散爱 提交于 2019-11-30 19:01:29
区间dp+决策单调性 题目链接 part1.朴素dp 记 \(dp[l][r]\) 表示l到r这个区间最坏情况下的最小花费。 那么考虑在 \([l,r]\) 中任选一个点k挖,此时有两种情况: 1.k点有油,那么后续代价就是 \(dp[k+1][r]\) 2.k点没有油,那么后续代价就是 \(dp[l][k-1]\) 显然,为了使情况最坏,我们要在 \(dp[k+1][r]\) 和 \(dp[l][k-1]\) 中取最大值。 而 要使最坏情况下花费最小 ,我们要在所有k中取最小值。 那么,转移方程就是: \[ dp[l][r]=min\{max\{dp[l][k-1],dp[k+1][r] \}+A[k]\} k\in[l+1,r-1] \] 其中 \(A[i]\) 表示在点i勘测是否有油的花费。 这样,就有一个 \(O(n^3)\) 朴素dp了,期望得分30分。 part2.决策单调性优化 我们要的是 \([l,r]\) 的最小值,所以应该是维护单 调递增的 队列。 但还有一个问题,转移方程中有 \(max\{dp[l][k-1],dp[k+1][r] \}\) ,我们要想办法把这个max消掉。 那如何消去max呢? 我们维护一个k,使得 \(dp[l][k-1]\) 刚好大于 \(dp[k+1][r]\) 或者 \(dp[k+1][r]\) 刚好大于 \(dp[l][k-1]\

bzoj 4722 由乃

三世轮回 提交于 2019-11-30 15:10:55
bzoj 先考虑一种简单的情况,即这个区间是否有相同的数,因为值域大小为1000,那么当区间长度 \(>1000\) 时,根据鸽巢原理,一定会有两个相同的数,这时候可以直接输出 Yuno 进一步的,对于长度为 \(len\) 的区间,子集的值域为 \([0,v*len]\) ,子集个数为 \(2^{len}\) ,那么可以得到如果满足 \(2^{len}>v*len+1\) 的区间,一定有两个一样权值的子集(有交就把交去掉),可以解得这个界为 \(len\ge 14\) .那么对于 \(\le 13\) 的部分,就 暴力枚举每个数在哪个集合中,或者是不在集合中,复杂度 \(O(3^{len})\) ,其实可以 \(meet in the middle\) ,先搜前一半,得到所有选取情况下 \(A\) 集合权值 \(-B\) 集合权值的值,然后搜另一个集合,直接查是否存在对应 \(A\) 集合权值 \(-B\) 集合权值的相反数,以及是否有那个值为0的方案,复杂度 \(O(3^{\frac{len}{2}})\) 至于修改操作,那么每次询问这个值的时候给他修改总修改次数-以及修改次数 次,因为这个修改可以看成在有向图上走 \(x\) 步,所以可以预处理走一些步数的情况,修改时直接大力跳即可 #include<bits/stdc++.h> #define LL long long

BZOJ 2200 道路与航线

做~自己de王妃 提交于 2019-11-30 05:50:36
题意 有N个点的图,M条双向边,K条单向边,只有单向边可能为负,并且含有单向边的路径不是回路,求从S出发到所有点的最短路径长度 分析 由于有负权边,不能直接上spfa。相信小伙伴们一定看过了《算法竞赛进阶指南》,所以与书上重复的就不再讲了,只罗列一些我自己思考到的东西 如果按照拓扑序,一定会有一个连通块入度为0吗?答案是一定会有的,如果没有,那么肯定有一条含有单向边的路是回路。 s点所在连通块入度不为0会怎么样?其实并不会怎么样,说明那些入度为0的连通块中的点都不能从s点出发到达。所以直接无脑按照拓扑序去扫就行了。在进一步讲,在存储拓扑序的队列中,跟s所在连通块深度相同的连通块中的点都是无法到达的。 做法思路主要切入点是只有单向边为负,而且不构成环,所以就把单向边所连的连通块看成一个点的话,整个图就是个DAG,DAG的最短路直接通过求拓扑序来求即可。 另外要注意一个细节是,每次处理一个连通块时,都是先把该连通块的所有点都放到优先队列中(想一下为什么要这么做) #include <bits/stdc++.h> using namespace std; const int N = 25000; const int M = 200010; const int inf = 0x3f3f3f3f; vector<int> vec[N]; int fa[N],head[N],ver[M]

BZOJ 2431 [HAOI2009]逆序对数列 (dp)

為{幸葍}努か 提交于 2019-11-30 03:22:29
题意 问长度为n的1~n的排列,且逆序对为k的方案数有多少 \(n,k\leq 1000\) 思路 假设前 \(1\) ~ \(i\) 已经排列好,此时逆序对为 \(k\) ,那么我们来讨论插入 \(i+1\) 时候的状态 \(i+1\) 根据插入位置的不同,可以产生 \(0\) 到 \(i\) 个逆序对 根据这个特点我们设 \(dp[i][j]\) 为前 \(i\) 个数,逆序对为 \(j\) 的排列的方案数 \(dp[i][j]=f[i-1][j-i+1]+f[i-1][j-i+2]+\cdots +f[i-1][j]\) 代码 #include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<cstring> #include<string> //#include<stack> #include<queue> #include<deque> #include<set> #include<vector> #include<map> #define fst first #define sc second #define pb push_back #define mem(a,b) memset(a,b,sizeof(a)) #define lson l,mid,root<<1

bzoj 2208 //2208: [Jsoi2010]连通数

大憨熊 提交于 2019-11-29 23:44:36
bzoj 2208 //2208: [Jsoi2010]连通数 //在线测评地址 https://www.lydsy.com/JudgeOnline/problem.php?id=2208 更多题解,详见 https://blog.csdn.net/mrcrack/article/details/90228694 BZOJ刷题记录 //2208: [Jsoi2010]连通数 //在线测评地址https://www.lydsy.com/JudgeOnline/problem.php?id=2208 //第一个思路,Floyd算法,求最短路径,算法的时间复杂度O(n^3),看了数据范围 N不超过2000,只好作罢 //统计 连通数 时,采用O(n^2)算法即可 //问题是,如何确认2点连通,这个算法的时间复杂度,如何降下来。 //多点的连通问题。 //强连通分量及缩点tarjan算法解析https://blog.csdn.net/acmmmm/article/details/16361033可看此文,手绘图。 //初探tarjan算法(求强连通分量) https://www.luogu.org/blog/styx-ferryman/chu-tan-tarjan-suan-fa-qiu-qiang-lian-tong-fen-liang-post 此文值得一看 /

BZOJ 3251. 树上三角形

北城余情 提交于 2019-11-29 23:21:24
传送门 看到这种奇怪的要求,考虑一下推结论 考虑把路径上的点权拿出来排序,变成一个数列,那么显然我们只要考虑相邻连续的 $3$ 个数 发现如果我们贪心构造一个尽量无法构成三角形的数列,那么最小的数列就是斐波那契数列 众所周知斐波那契数列增长很快,第 $50$ 项显然远大于题目给出的点权范围,所以如果 $u,v$ 之间点数大于等于 $50$,那么鸽巢原理一下显然一定能构成三角形 所以如果 $u,v$ 之间点数超过 $50$ 直接输出 $Y$ 即可,否则我们再暴力判断即可 这个实现就一倍增 $LCA$ #include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> using namespace std; typedef long long ll; inline int read() { int x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } return x*f; } const int N=2e5+7; int