做题记录1
做题记录1:
P4587 [FJOI2016]神秘数
解法:主席树。
题目大意:给定n个数,求 l~r中的数的子集和不能表示出的最小数。
首先考虑暴力的解法:
将l~r中的数排序,设前 i 个数的和为sum 如果 \(a_{i+1}>sum+1\) 则sum+1无法表示,答案则为sum+1
这个时候可以用一种迭代法模拟这个过程,不妨我们设上一次的sum为pre:初始将sum=0,然后查询pre~sum+1数的和,然后将sum累加上这段和,直到这段区间没有数。显然:每次加的数\(\in[pre,sum+1]\) 那么每一次的累加要么没有直接停止,要么至少翻倍。
再用一个主席树维护就行了,复杂度 \(\Theta(n\log^2n)\)
2020牛客NOIP赛前集训营-提高组(第一场)D 牛牛的RPG游戏
解法:CDQ套李超树
题意:(简要题意略去)
一个朴素的DP方程:\(dp[i][j]=max(dp[i][j],dp[x][y]+val[x][y]+buff[x][y]*(i+j-x-y)) (x\leq i,y\leq j)\)
这个柿子长得就很想一个李超树。
用一个cdq维护整个矩形内关于 \(x,y\) 的偏序,然后用一个李超树维护就好了。
细节:首先插入直线的k值显然为buff值,但是b值通过一些容斥:显然就是本身的dp值+本身的val值-(x+y)*buff。
P4550 收集邮票
期望DP,倒着递推,设 dp[i] 表示已经取了 i 个,期望还需要取多少次,g[i] 表示取得期望价格。
显然有:
f[i]=f[i+1]+(1.0*n)/(1.0*(n-i));
g[i]=(1.0*i)/(1.0*(n-i))*(f[i]+1)+g[i+1]+f[i+1]+1;
P1654 OSU!
期望DP,较为简单的期望DP。
首先设前面一段有 \(x\) 个 1,那么当前又为 1所带来的差值也就是 \((x+1)^3-x^3=3*(x^2+x)+1\)
那么维护前缀中的 \(x^2,x\) 的期望,就可以求出 \(x^3\) 的期望了。
P4097 [HEOI2013]Segment
李超线段树模板题,区别为区间修改的李超树。
P4655 [CEOI2017]Building Bridges
李超线段树优化斜率优化DP。
很简单的模型随便推推柿子就出来了。
注意动态开点节点为空的时候的返回,上一道题Segment
可以返回 0,因为要求的是编号,而这次返回值,因为要求最小所以返回INF。
P6085 [JSOI2013]吃货 JYY
3进制状压DP神仙题
给定 n 个点,\(n \leq 13\) ,K 条必选边,\(K \leq 78\),还有M个可选边(非必须边)。\(M \leq 200\)
以上的边皆为无向带权。
求从 1 号点开始,经过K条必选边,最后回到 1 号点的最小花费。
首先:最后形成的一条路径最优的话一定是一条欧拉回路。
那么形成一条欧拉回路的必要条件就是:每个点的度数一定为偶数。n 又很小,于是用一个3进制状压表示状态。
-
0 表示该点未与 1 连通
-
1 表示该点连通且度数为奇数
-
2表示该点连通且度数为偶数
这个 dp 数组表示的应该是该状态下的点集,通过若干条非必须边与若干条必须边连接后,只考虑非必须边的度数;非必须边的权值的和的最小值。
那么转移的时候可以用一种类似于SPFA的样子转移:
先对于当前点集枚举未在点集中的点:
那么有两种转移:
- 1.这个点通过一条必须边和当前点集中的点相连:那么直接转移。
- 2.枚举当前在点集中的点,改变该点的度数,通过最短路与这个点连接。
需要注意的是,每个状态都必须扩展一次,所以记得加入待选队列。
那么此时就到了统计答案的时候了:
枚举状态,然后根据必须边加入的度数将状态修改为完整的状态。
再加上将所有的奇数度数点变为偶数的代价:(这个需要一个二进制状压+Floyd预处理)
就是所有的必须边再+之前求出的最小值就可以了。
(Q:为什么最短路中的 dis 是包含必须边的 ?A:反正更优,我重复走一次又有什么关系呢?)
P7098 [yLOI2020] 凉凉
for (int s = S; s; s = (s - 1) & S)
精确枚举子集+神仙预处理
P2746 [USACO5.3]校园网Network of Schools
根据协议,为了让网络中所有的学校都用上新软件,必须接受新软件副本的最少学校数目 任务A
我们想要确定通过给任意一个学校发送新软件,这个软件就会分发到网络中的所有学校。任务B
缩点
A显然为缩完点入度为0的点。
B就是把当前图变为连通图的最少边。一个连通图所有的点出度和入度一定不为0。
所以最少的边肯定就是将入度为0的点和出度为0连接。那么边数就是两者取min
注意特判只有一个scc的时候答案为 0,这个时候不用连接。
Codeforces Round #745 (Div. 2) A
当一个排列的度为 \(x\) ,那么将这个排列反过来的就为 \(2n-1-x\) ,两者有且只能有一个 \(\geq n\) ,所以答案为 \(\frac{n!}{2}\)
Codeforces Round #745 (Div. 2) B
小构造题,给定一个 n 个点 m 条边的图,问有没有可能让他成为一个连通且直径严格小于k-1 的图。
直径的定义是两点最短距离的最大值。
很显然菊花图构造,在瞎特判特判就好了。
Codeforces Round #745 (Div. 2) C
问一个01矩阵,将一个子矩形 4条边界除了4角都改为1,边界里面的都改成0的最小操作次数,其中长 \(\geq5\) ,宽\(\geq 4\)
数据范围就是在暗示一个 \(n^3\) 做法。
如果枚举了子矩形的上下边界,考虑如何确定当前的最小左右边界:
枚举右边界,加入当前的右边界在 \(i\) ,那么对于 \(j\in[1,i-1]\) 预处理出左边界为 \(1\) ,右边界为 \(j\) 的所有矩形的 上边界+下边界+左边界 - 右边界,如此维护一个前缀max,再用当前表示 \([1,i]\) 的矩形的 上边界+下边界+左边界+右边界 - MAX 就可以了。
复杂度显然为:\(\Theta(n^3)\)
10.1 模拟赛 A题。
显然,一个名词组只要最后一个字母是名词,中间没有只能是动词的词便可以组合成为一个名词。
于是枚举一个句子的动词分界点,判断前缀与后缀中有无强制是动词的,然后判断前缀与后缀的最后一个字母是否可以作为名词存在即可。
10.1 模拟赛 B题
双向链表维护,push操作显然就是在 z 后面插一个点。
pop 用了链表的话,可以直接暴力弹出,复杂度分析:就是每一个点进一次出一次,所以还是 \(\Theta(n)\) 的。
put 的话,因为它是从尾到头再插入的,所以pre 和nxt其实是混着用的,只需要每次跳的时候保证不会跳回来就好了。
于是push操作也要魔改魔改。。因为可能 tail 的pre里面存的才是nxt。
剩下的就没什么了,push和put 显然O(1)。
10.1 模拟赛 C题 (代码待补)
牛逼线段树,待补题。
10.1 模拟赛 D题(代码待补)
牛逼倍增,待补题。
10.2 启智树模拟赛 A
简单的基于交换的贪心,懒狗作者选择跳过。
10.2 启智树模拟赛B
好玩的构造题,最终构造出来就是原本的一个高维体复制一遍然后和原本的高维题对应点连边就可以升一维。
然后考虑怎么样只有奇数个黑色边:
将复制的高维体变为原本的高维体取反。
此时的高维体还是合法的(偶-奇=奇)。
此时再将对应点都连起来,且为白边。
新形成的面保证只有一条黑边。
10.2 启智树模拟赛 C
最优策略下:一定是 y 先攻击若干次,然后 x,y交替攻击若干次,最后 x 拿下人头。
那么不妨设 y 先攻击 \(inc_i\) 次,\(x,y\) 交替攻击 \(nd\) 次。
很显然 \(y*inc_i>=a_i\) ,所以很容易列出来inc和nd的求柿子:
inc[i]=(a[i]+y-1)/y;
nd[i]=(a[i]-(inc[i]-1)*y+x-1)/x;
我们设一个 now 表示 x 可以打当前敌人的次数。
然后对于一个敌人有三种情况:
1.放弃不打,此时 \(now+=inc_i\) ,ans不变
2.打,那么就必须能够打掉,也就是 \(now+inc_i-nd_i-1>=0\) ,ans++
3.打,但是现在打不掉,那么我们看看之前打过的,如果耗费的 \(nd_i\) 更多,显然打这个更加的合适,ans不变,now加上两者差值。
贪心反悔好题只能说是。
10.2 启智树模拟D(代码待补)
首先可以根据期望的定义列出一个柿子:然后化简可以得到答案就为:\(\sum\limits_{i=1}^{n}P(x\geq i)\) (指选择到的路径数量 \(\geq i\) 的概率)
设树上不同的路径数量为 \(cnt\) ,如果确定了操作步数为 \(i\) ,那么 \(P(x\geq i)\) 就是在树上选择 \(i\) 条有序的不相交路径的方案数除以 \(cnt^i\),可以通过一个树形背包的DP得到选择 \(i\) 条 无序 的不相交路径的方案数,除以阶乘就可以得到 i 条有序的不相交路径的方案数。
时间复杂度 \(\Theta(n^2)\)
10.3 启智树模拟A
注意到开始后反射两次后就会进入一个在平行四边形里面反射的循环,直接递归处理就好了,每次有 mod 所以时间复杂度为 \(\Theta(\log n)\)
10.3 启智树模拟B
注意到 \((mid,mid)\) 处一定是最优的,选的总点数为 \(k\) ,于是直接往 4 个方向扩展然后用一个优先队列跑类似dj的东西就好了。
考场把这个算法复杂化了,用了一个优化反而没有写出来。。。
10.3 启智树模拟C
首先处理出从 st 走偶数步能到达的点的集合,设为 \(S\),其他点的概率显然为 0 ,设 sum 为每一个点的边权和,\(tot=\sum\limits_{x\in S} sum_x\),集合内的点为\(P(x)=\frac{sum_x}{tot}\),这个要通过一个什么偶数步概率的收敛值算,表示不会。
10.3 启智树模拟D(代码待补)
结论:对于一个小正方形,如果上方的三明治先取,则一定要取完上方的小正方 形,同时上面那个小正方形同样也要先取上面的三明治。对于向下,向左,向右
同样有 这个性质。 因此,对于问题:先取 \((i, j)\) 中某一个三明治,再取另一个的限制将会在每个涉及 到的小正方形上沿着两个方向“传播”,可以通过 \(dfs\) 求出最
优方案。
考虑对于小正方形 \((i, j)\) ,假设先取左边的三明治,则它的最优方案一定是在对小 正方形 \((i, j − 1)\) 先取左边的三明治的最优方案的基础上再多吃一些得到的。那么
可以 一行一行的做,对于每一行 i,从左到右枚举 j, 然后在 \((i, j − 1)\) 方案的基础上 \(dfs\) 求 出 (i, j) 先取左边的三明治的最优方案。对于先取右边的情况,同样做一
遍,最后在两 种情况中取较优的即可。注意判断无解。 每一行的时间复杂度为 \(\Theta(nm)\),总复杂度为 \(\Theta(n^2m)\)。
10.4 启智树模拟A
一定存在一种构造方案使得答案为所有边权的和。
10.4 启智树模拟B
显然每一个点的答案=从最外围向里面走的所有路径中的高度的最大值的最小值。
直接相邻点建边为两点高度max然后跑最短路就好了,记得判断无解。
10.4 启智树模拟C
10.4 启智树模拟 D
10.5 启智树模拟 A
注意到 \(k\) 很小,那么显然可以直接用容斥硬算。
直接 Dfs 即可,注意组合数的取模和 Dfs 的细节。