退役前的做题记录2
[HNOI/AHOI2018]游戏
一个想法就是预处理出每个点向左和向右拓展多少,\(O(1)\) 回答询问。
暴力容易被卡。
正解比较牛逼,先把没有门的缩成一个连通块,对于相邻两个连通块 \(i,i+1\) 来说,如果 \(i\) 到 \(i+1\) 需要的钥匙在 \(i+1\) 之后,那么 \(i\) 不能到达 \(i+1\),此时肯定是先处理 \(i\) 更优;否则处理 \(i+1\) 更好。
那么可以连成一个具有拓扑关系的 \(DAG\),按照拓扑序扩展即可。
因为每个连通块只会扩展一次,所以复杂度线性。
[HNOI2018]排列
第一步转化,令 \(q[p[i]]=i\),那么题目变成:
有一些 \(q[a[i]]<q[i]\) 的限制,\(q\) 必须为排列,求 \(max(\sum_{i=1}^{n}w[i]q[i])\)
这个东西是可以建图的,\(i\rightarrow a[i]\),不合法当且仅当有环
其它情况就是一棵树(\(0\) 为根)
也就是在这个树上依次选点,选 \(u\) 之前必须选择其父亲,第 \(i\) 次选的代价为 \(i\times w[u]\)。
考虑贪心,对于一个当前权值最小的点 \(u\) 来说,如果父亲是 \(0\),那么肯定选它最优
否则,设父亲为 \(fa\),那么选完 \(fa\) 之后一定会选 \(u\),这样就可以合并这两个节点。
对于之后已经合并过的节点,设其权值和为 \(v[i]\),大小为 \(c[i]\)
那么 \(i\) 先于 \(j\) 当且仅当
\(v[i]+c[i]\times v[j] \le v[j]+c[j]\times v[i]\)
也就是 \(i\) 的平均权值最小,以这个为关键字选最小的点就行了。
为了计算答案,把每个点的贡献在合并的时候拆开计算即可。
[HNOI2018]毒瘤
容斥+ \(DP\) 有 \(75pts\)
正解可以动态 \(DP\),或者维护 \(22\) 个关键点的虚树,每一条链的转移系数不变,预处理即可。
[JXOI2018]游戏
不难发现,所有不能被其他数筛掉的数是一定要选的,只有选了这些数字才能结束
假设有 \(m\) 个,枚举结束时间 \(x\),答案就是 \(\sum \binom{x-1}{m-1}m!(n-m)!x\)
埃氏筛法即可求出 \(m\)
(埃氏筛法复杂度 \(O(nloglogn)\) !!!)
[JXOI2018]排序问题
不难看出期望就是 \(\frac{(n+m)!}{\prod_{v=1}^{max}(cnt_v!)}\),\(cnt_v\) 表示 \(v\) 这个数出现的次数。
贪心就是直接把 \(m\) 个数字每次选择一个 \(cnt\) 最小的加入,使得最后 \([l,r]\) 内每个数字出现的的次数尽量平均。
直接按照数字出现的次数排序,从大到小枚举平均的次数是多少即可。
[JXOI2018]守卫
假设不能被n看到的是很多个区间 \([l_k,r_k]\)
不难发现一个性质:\([r_k+2,n]\) 的位置是看不到 \([l_k,r_k]\) 的位置的。所以 \(r_k,r_k+1\) 必选其一。
我们还注意到,对于 \(j<k,[l_k,r_k+1]\) 的位置是看不到 \([l_j,r_j]\) 的位置的,也就是说这些区间互相独立。
然后就可以直接 \(DP\) 了。
[HAOI2018]奇怪的背包
不难发现一个性质:选出来的集合 \(S\) 要满足 \(gcd(S,P)|w_i\) 才合法。
把 \(P\) 的约数取出来 \(v_i\) 取 \(gcd\) 之后容斥即可
复杂度 \(O(d^2(P))\),\(d\) 为 \(P\) 的约数个数。
[HAOI2018]苹果树
设 \(i\) 个点的树的方案数 \(f_i\),到根的距离和为 \(g_i\),距离总和 \(h_i\)
显然 \(f_i=i!\)
\(g_i\) 的合并要将左右的树的 \(g\) 分别加上 \(1\)
\(h_i\) 的合并要将左右的树的 \(g\) 分别加上 \(1\) 然后拼起来再加上左右的 \(h\)
最后 \(h_i\) 还要算上 \(g_i\)
更加优秀的做法
可以考虑每个子树的贡献,对于一棵 \(i\) 的子树,大小为 \(x\),方案数为 \(\binom{n-i}{x-1}\times x!\),贡献为 \(x\times(n-x)\)
对于子树外面的情况,就是 \(i!(i-1)i(i+1)...(n-x-1)=(n-x-1)!i(i-1)\)
直接计算即可
[HAOI2018]反色游戏
不难发现就是给你 \(n\) 个异或方程组,求解的个数。
下面假设都是有解的情况
对于一棵树来说,显然解最多一个,每次父亲消去儿子的即可。
不难得到,如果有 \(x\) 条非树边,无论它们怎么选择,都一定有唯一的解,方案数就是 \(2^x\)
设有 \(n\) 个点,\(m\) 条边,\(c\) 个连通块,答案就是 \(2^{m-n+c}\)
只要讨论每个连通块是否有偶数个黑色即可判断无解。
每次删除一个点:分成割点,非割点讨论即可。
[HAOI2018]字串覆盖
思想比较简单。
对于 \(r-l+1 > 50\) 的询问,直接暴力贪心的每次选择最靠前的位置匹配即可,SAM+线段树+倍增可以很好的实现。
对于 \(r-l+1 \le 50\) 的询问,离线下来,对于长度相同的倍增处理出上述的操作即可。
还是挺好写的
[JSOI2018]列队
不难发现一定是把区间 \([l,r]\) 排序之后一一匹配最优(交叉匹配肯定不优)。
同样也不难发现一定存在一个分界点 \(x\) 使得小于等于 \(x\) 的 \(a_i\) 的位置小于等于匹配的点,另外大于 \(x\) 的相反。
主席树上二分就好了。
[JSOI2018]防御网络
显然是要考虑每一条边的贡献,对于一条非树边(割边),只要从它分开的两个集合中各选大于 \(0\) 个点就好了。
主要的问题是环上的边,不难发现,如果环上有 \(k\) 个点,那么最长的那个间隔一定不会在斯坦纳树里面。
可以枚举环上第一个选的点为 \(st\),然后设 \(f_{i,j}\) 表示前 \(i\) 个,最大间隔为 \(j\) 的方案数(每个点个贡献为 \(2^{x}-1\) 的形式),可以用前缀和优化轻易优化到 \(O(n^3)\)。
n的4次方也挺快的
[JSOI2018]绝地反击
第一想法是二分答案+二分图匹配,合法的偏转角只会是那些弧的端点,\(O(n^4logn)\)
又因为偏转角不会超过 \(\frac{2\pi}{n}\),那么可以在模 \(\frac{2\pi}{n}\) 意义下一路扫过去。每次最多加入(删除)一条边,退流即可。
[JSOI2018]机器人
神仙题,给结论跑路
设 \(d=gcd(n,m)\),那么每一个 \(d\times d\) 的正方形矩阵同构,操作每 \(d\) 个一个循环。
设向右 \(x\) 步,向下 \(y=d-x\) 步,合法的方案当且仅当 \([x\perp d][x\perp n][y\perp m]\)
转换:碰到障碍前走的路程 \(=\) 碰到每个障碍时走的路程的最小值。
处理出每个点 \((x,y)\) 在循环内走到的第一个障碍的距离,之后 \(DP\) 即可
[FJOI2018]所罗门王的宝藏
每个宝石的行和列连边,表示两者的操作的和为边权
有解则同一个连通块每个点一定可以用每个点的一次函数表示,\(dfs\) 即可
[FJOI2018]领导集团问题
一个显然的 \(DP\):
\(f_{u,i} = [i=w_u] + \sum_{v \in son_u}max_{j \ge i} f_{v,j}\)
可以直接用线段树合并维护,每次把右边的最大值丢到左边合并更新 \(max_{j \ge i} f_{v,j}\)
正确性:刚开始合并上来的 \(max_{j \ge i} f_{v,j}\) 一定是单调的。
最后只要单点修改即可。
[FJOI2018]邮递员问题
乱搞。
可以发现如果起点在左边界,终点在右边界的时候上下走的点一定是连续的(可能吧)
那么可以设 \(f_{i,j,0/1}\) 表示当前上面到 \(i\),下面到 \(j\),当前在上面/下面的最短距离。
如果起点不在左边界,终点不在右边界,那么就乱搞。
对于左边,如果向左的时候下去了再上来一定不会优与直接走过去,那么就分两种情况:左下右 或者 直接先左再次原路返回向右。
右边类似,每次到一个点用这个策略更新一下答案。
之后交换左右再做一遍即可不想卡常了,BZOJ直接特判了QwQ
上述(假算法)策略成功水过了所有的测试点。
[TJOI2018]游园会
经典 \(DP\) 套 \(DP\) 。
[BJOI2018]求和
模拟即可。
[BJOI2018]二进制
一个显然的结论,设串的长度为 \(n\),有 \(x\) 个 \(1\)。
那么合法当且仅当:\(x\) 为偶数或者 \(x\) 为奇数 \(x>1\) 且 \(n-x \le 2\)
也就是两种情况:偶数个 \(1\) 或者奇数个 \(1\),大于 \(1\) 个 \(1\),且大于 \(1\) 个 \(0\)。
设一个 \(f_{0/1,0/1/2,0/1/2}\) 全部记录下来即可,线段树上就维护前缀和后缀。
合并的时候直接 \(for^6\) (逃
本机稳定 \(0.95s\),然而BZOJ还是TLE了
[BJOI2018]治疗之雨
设 \(c_i\) 表示 \(k\) 轮打中了 \(i\) 次的概率,\(c_i=\binom{k}{i}(\frac{1}{m+1})^{i}(\frac{m}{m+1})^{k-i}\)
设 \(f_i\) 表示当前 \(i\) 的生命值,到死去的期望。
\(f_0=0\)
\(f_i(1\le i < n)=\frac{1}{m+1}\sum_{j=0}^{i+1}f_{j}c_{i-j+1}+\frac{m}{m+1}\sum_{j=0}^{i}f_{j}c_{i-j}+1\)
\(f_n=\sum_{i=0}^{n}c_if_{n-i}+1\)
设 \(x=f_1\),把所有的 \(f_i\) 表示成 \(a_ix+b_i\) 的形式求解即可。
我怎么又在BZOJ上TLE了???
[BJOI2018]链上二次求和
线段树维护二维前缀和即可,讨论一下标记的系数。
最近随便写个题在BZOJ都TLE了QwQ
[BJOI2018]染色
大前提:肯定是二分图才有可能合法。
一条长度为奇数的链是可以直接 \((A,B)\) 缩成一个点。
然后是各种情况:
(a)对于同一个连通块,存在两个环之间最多只有一条公共点,可以通过一个环强制一个点的颜色卡掉。所以环都要交织在一起。。
(b)对于两个环,如果它们的交是奇数(大于 \(1\)),并且各自不交的部分大于 \(1\),也可以卡掉:
可以通过左边的环构造出交的两端至少有一个为固定的颜色,经过另一个环可以使得交的另一个端点的颜色不同,这样就卡掉了。
(c)对于两个环,如果它们的交是偶数(大于 \(1\)),并且各自不交的部分大于 \(1\),也可以卡掉:
使得交的两个端点都是 \((A,B)\),那么可以把交的都变成 \((A,B)\),这样端点必定不同,只有两种情况,分别在左右的环中卡掉。
(d)剩下的情况:一个连通块就是一个简单环或者树;两个环的非交部分都是 \(1\);可以发现这样的东西怎么玩都卡不掉。
这个题目怎么这样啊
综上所述,最后合法的图的情况:
(a)一个连通块中 \(n\ge m\)
(b)一个连通块中 \(n+1=m\),且是两个环的非交部分都是 \(1\) 的情况。
[BJOI2018]双人猜数游戏
好神啊,反正这个游戏我是不会玩。。。
考虑 \(Alice\) 一次不知道会告诉 \(Bob\) 什么,显然 \(Bob\) 可以穷举自己的每一种可能的方案,看看是否有可能使得 \(Alice\) 的方案唯一。
\(Bob\) 不知道同理。
所以可以直接设 \(f[i][j][k]\) 表示第 \(i\) 轮,两个人是否都不知道 \(j,k\) 这组数字,记忆化搜索即可。
[ZJOI2018]胖
处理出每个与 \(0\) 相邻的点能更新的区间 \(L_i, R_i\),\(ans=\sum (R_i-L_i+1)\)。
可以通过二分 + 线段树实现,边界情况比较难以判断,注意一下。
[九省联考2018]一双木棋chess
爆搜,状态不多,直接 \(hash\) + 记忆化
Codeforces 891C:Envy
因为最小生成树的性质,分开考虑相同边权的边能否加入,只要预处理出加入小于某个边权的边之后的图的连通性即可判断。
一个不用可持久化并查集的方法就是:记录下每一条边在边权小于它的所有边之后的端点的连通块编号。
Atcoder2134:Zigzag MST
因为 \((a,b,c)\) 边权大于 \((a+1,b,c+1)\),那么 \((a,b)\) 肯定会在 \((a+1,b,c+1)\) 之前就连通。
那么在不改变连通性的情况下显然可以把 \((a+1,b,c+1)\) 变成 \((a,a+1,c+1)\)
这样加边就变成了 \((a,b,c),(a,a+1,c+1),(b,b+1,c+2)...\)
把 \((a,b,c)\) 单独拿出来,加上相邻两个点的最短边做 \(kruskal\) 即可。
Atcoder3611:Tree MST
点分治,每次考虑把所有的子树连通,显然是离分治中心最近的点向所有的点连边,这样肯定比其它连法更优。
[Snoi2017]炸弹
左边和右边第一个能爆炸这个点的点向这个点连边,单调栈可以实现。
\(tarjan\) 缩点之后,变成求 \(DAG\) 能到达的点的个数。
由于题目性质,到达的点一定是一个连续的区间,记录左右端点即可。
复杂度 \(O(n)\)
[JSOI2012]越狱老虎桥
拿出所有的割边排序,找到一个恰好不能用一条链覆盖的前缀,输出这个前缀的最后的边权即可。
然后我就写了个二分。。
牛客Wannafly挑战赛9 E:组一组
分开考虑每一位,前缀和之后差分约束。
注意相邻两个前缀和 \(S_i,S_{i+1}\) 要满足 \(S_i \le S_{i+1}\),且 \(S_{i+1}\le S_i+1\),因为最多有一个二进制位的贡献。
剪枝
BZOJ4886: [Lydsy1705月赛]叠塔游戏
显然每种宽度只选择一个就可以了,对于一个卡牌,连边 \((a_i,b_i)\)。
最后就是要给边定向,答案为每个点的出度乘以权值。
因为题目保证有解,那么一个连通块要么是树,要么是基环树。
对于树,选择权值最大的点作为根即可。
对于基环树,怎么选每个点都要有 \(1\) 的入度,所以不用管。
以上均可以用并查集实现。
Codechef:Querying on a Grid
分治,类似于“[ZJOI2016]旅行者”维护每个分治中心三个点的最短路径树。
查询距离就是找到每一个包含这个区间的分治中心,取距离 \(min\)。
修改就是找到其中一个满足距离等于最短路的分治中心,单点修改,子树查询。
查询点就是找到所有包含这个点的分治中心,求和。
牛客Wannafly挑战赛4 F:线路规划
最小生成树。
树上用 \(ST\) 表优化连边,注意不能首先连接到 \(ST\) 表上之后 \(pushdown\),因为不能确定下面的点的连通情况。
做法是每次暴力递归 \(ST\) 表连边,碰到连好了的就返回。
因为 \(ST\) 表一共 \(log\) 层,每一层只会合并 \(O(n)\) 次,所以复杂度正确。
LOJ6036:「雅礼集训 2017 Day4」编码
\(trie\) 加链上前后缀连边,连完之后求 \(2-sat\) 即可。
UOJ236:[IOI2016]railroad
题目可以转化成这样:
给定一些有向边 \((s_i,t_i)\),你需要加入一些边使得存在欧拉路径,并且图连通。
边权:向左连边代价为距离,向右连边无代价。
求最小代价。
首先可以加入边 \((inf,1)\),这样就变成了欧拉回路问题。
我们考虑数轴上的一个间距,如果存在欧拉回路,那么在这个间距上向左和向右的边的数量必须相等。
那么可以先求出每个间距的贡献。
但是这样只能使一段还需要加边的区间连通。
所以再把相邻两个不连通的区间之间的边拿出来跑一遍最小生成树即可。