码迷,mamicode.com
首页 > 其他好文 > 详细

一些数据结构杂题简要题解

时间:2020-01-18 21:35:28      阅读:102      评论:0      收藏:0      [点我收藏+]

标签:逆序对   维数   要求   全排列   排列   lin   概率   维护   计算   

[POI2015] Kinoman

二维数点问题,常用套路是,枚举其中一个端点,然后维护到每个端点的区间的值

设一部电影上一个播放日为 \(pre_i\),下一个播放日为 \(nxt_i\),发现每场电影 \(i\) 只有在 \(l > pre_i,r<nxt_i\) 的区间中对答案有贡献。

所以我们先将所有区间按照 \(pre_i\) 从小到大排序,从左到右枚举左端点,维护一棵以右端点为下标的线段树,每次将 \(pre_i<l\) 的点在区间 \([i,nxt_i)\) 加入贡献,并将 \(pre_i<l\) 的点的贡献删除,每次取全局最大值即可。

代码

ARC068E Snuke Line

对于每个 \(d\),如果一个商品的区间长度 \(\ge d\),那么这个商品一定会至少覆盖一个为 \(d\) 的倍数的点,所以直接计入贡献,而对于那些区间长度 \(<d\) 的商品,最多只会覆盖一个点,所以不会算重,直接树状数组进行区间修改、单点查询即可。

代码

CF749E Inversions After Shuffle

题意:给出一个 \(1 \sim n\) 的排列,从中等概率的选取一个连续段 \([l,r]\),设其长度为 \(l\)。对连续段重新进行等概率的全排列,求排列后整个原序列的逆序对的期望个数。

直接计算区间的期望不太好计算,由于期望的线性性,考虑计算每一组点对 \((i,j)\) 的贡献。

  1. \([l,r]\) 完全包含 \((i,j)\),逆序对的期望个数为 \(0.5\)。对答案的贡献为
    \[ \frac{\sum \limits_{i=1}^{n} \sum \limits_{j=i+1}^{n} 0.5\times i (n-j+1)}{\frac{n(n+1)}{2}} = \frac{\sum \limits_{i=1}^{n} \frac{i(n-i+1)(n-i)}{2}}{n(n+1)} \]
    于是就可以 \(O(n)\) 地算出来了。

  2. \([l,r]\) 不完全包含 \((i,j)\)。若 \(w_i < w_j\) ,则对答案的贡献为 \(0\)。若 \(w_i > w_j\) ,逆序对的期望个数则为 \(1\),所以对答案的贡献为
    \[ \frac{\sum \limits_{i=1}^{n} \sum \limits_{j=i+1}^{n} \frac{n(n+1)}{2} - i (n-j+1)}{\frac{n(n+1)}{2}} \= 1- \frac{\sum \limits_{i=1}^{n} \sum \limits_{j=i+1}^{n} i (n-j+1)}{\frac{n(n-1)}{2}} \= 1- \frac{\sum \limits_{i=1}^{n} i\sum \limits_{j=i+1}^{n}(n+1-j)}{\frac{n(n+1)}{2}},且w_i>w_j \]
    所以这部分只需要对每个位置用树状数组维护其后面比它小的数的数量以及位置的和即可。

    代码

CF901C Bipartite Segments

首先,“不含偶环的无向图”是仙人掌,而二分图的充要条件是不含奇环,所以诱导子图必须是不含环。

先用 \(\text{Tarjan}\) 缩点,求出每个环的编号范围 \([l,r]\),那么考虑对每个端点求出最大的合法的右端点 \(nxt_i\)

对于每个询问,二分出使得 \(nxt_i\) 大于 \(y\) 的临界点。然后在临界点后的肯定无论如何都是合法的,直接计算即可。在临界点前的,利用 \(nxt_i\) 加个前缀和进行计算即可。

代码

CF903G Yet Another Maxflow Problem

首先将最大流转化为最小割。

显然 \(A_i\)\(B_i\) 都最多只会割一条边,枚举割 \(A_i\),如果割 \(B_j\),那么对于所有的边 \((x,y),x\le i, y\ge j\) 都必须割掉。那么我们可以枚举 \(A_i\),然后维护一棵以 \(B_j\) 为下标的线段树,依次将与 \(A_i\)相连的边加入线段树中,查询每一个 \(A_i\) 的答案取 \(\min\) 即可。

然后对于修改操作,由于只修改 \(A_i\) 的边,所以每个 \(A_i\) 所对应的最优的 \(B_j\) 是不会变的,所以只需要将每个 \(A_i\) 的答案用线段树维护,单点修改,查询全局最小值即可。

代码

[HEOI2016/TJOI2016] 排序

考虑二分,每次二分出一个 \(mid\) 时,将大于等于 \(mid\) 的数记为 \(1\),小于 \(mid\) 的数记为 \(0\),这样对于 \(01\) 串每次排序就只是 \(\log n\) 的了。最后再看一下第 \(q\) 位是否为 \(1\),如果为 \(1\) 说明答案可以更大。

代码

[SCOI2016] 萌萌哒

第一想法是线段树优化连边,但是由于线段树的可能会让两个对应区间的切割方式不一样,所以还是 \(O(N^2)\) 的。

考虑用 \(ST\) 表优化连边,令 \(fa[i][j]\) 表示 \(i\) 往后长度为 \(j\) 的区间在并查集上的父亲。然后标记下放即可。

代码

[2017 山东二轮集训 Day7] 国王

\(A\) 为两个端点都在 \([l,r]\) 中的合法路径条数,\(B\) 为两个端点都不在 \([l,r]\) 中的合法路径的条数,\(C\) 为两个端点不在同一个区间内的合法条数。

我们这里要求的是 \(A-B\),显然直接求不太好求,考虑我们求出 \(f_i\) 表示以 \(i\) 为其中一个端点的路径数,\(sum\) 表示总路径数,那么
\[ 2A + C = \sum\limits_{i=l}^{r} f_i \2B + C = 2 \times sum - \sum\limits_{i=l}^{r} f_i \]
所以
\[ A - B = \sum \limits_{i=l}^{r} f_i - sum \]
还是枚举左端点,显然合法的右端点是单调递增的。然后 \(f_i\) 可以利用点分治求。

一些数据结构杂题简要题解

标签:逆序对   维数   要求   全排列   排列   lin   概率   维护   计算   

原文地址:https://www.cnblogs.com/newbielyx/p/12210058.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!