Codeforces VP/补题小记 (持续填坑)

Codeforces VP/补题小记

1149 C. Tree Generator

给你一棵树的括号序列,每次交换两个括号,维护每次交换之后的直径。

? 考虑括号序列维护树的路径信息和,是将左括号看做 \(-1\) ,右括号看做 \(1\) ,那么一段竖直向上的路径可以表示为括号序列的一个区间和,一段竖直向下的路径可以看做括号序列的一个区间和的相反数。我们要维护的是树的直径,也就是一段连续的和减去紧随其后的一段连续的差。具体来说就是
\[
\max_{\forall [l,r]}\{\sum_{i=l}^kw[i]-\sum_{i=k+1}^r w[i]\}
\]
? 可以简单的证明如果选取的区间不能代表树上的路径,取到的式子的和一定不是最优解,线段树维护这个式子即可。维护起来略有麻烦,类似于维护区间最大子段和,更新的时候需要多记几个信息。复杂度 \(\mathcal O (n\log n)\) 。

1149 D. Abandoning Roads

\(n\) 个点 \(m\) 条边且仅有两种边权 \(a, b (a<b)\) 的无向简单图 \(G\),\(\forall i\) 求出 \(G\) 的所有最小生成树中,\(1-i\) 的路径的最小长度。\(1\leq n\leq 70,n-1\leq m \leq 200\) 。

? 这个题我一开始想了一个错误的做法,先求出最小生成树中 \(b\) 边的数量记为 \(k\) ,然后分别求出 \(1\) 到各个点经过不超过 \(k\) 条 \(b\) 边的最短路。这个做法的错误之处在于,虽然可以证明起始端点都在路径上的 \(a\) 边不会环切掉路径上的 \(b\) 边,但是只要令始端点在路径上就能环切了。

? 期间我还考虑了另外一种做法,后来得知后一种思路是可以扩展到正解的。考虑将所有 \(a\) 边缩成若干个联通块,不难证明,如果一条生成树的路径离开了一个联通块后又进入了这个联通块,这棵生成树一定不是最小生成树,因为其选择了会被环切的 \(b\) 边。此时直接大力状压 \(dp\) 的复杂度是 \(O(2^nm)\) 的。

? 再往下分析,如果一个联通块大小 \(\leq 3\) ,那么即使存在离开这个联通块后又来到这个联通块的路径,这条路径也必然不是最短路,因为这样联通块内部最长的边是 \(2a\) ,而做上述操作需要 \(2b\) 。所以可以直接忽视掉所以大小 \(\leq 3\) 的联通块的限制,复杂度优化到 \(\mathcal O (2^{\frac{n}{4}}m)\)。

1168 C. And Reachability

有一个长度为 \(n\) 的序列 \(A\) , \(i,j\) 之间有一条有向边当且仅当 \(i < j, A[i] \text{ and } A[j] > 0\) ,每次给出 \(x, y(x<y)\) ,询问从 \(x\) 出发是否能到达 \(y\) 。

? 按位考虑,对于当前数 \(A[x]\) ,其能直接到达后面所有和其有共同位的数。显然,对于每一位,较前面的数能到达较后面的数,所以只需要维护每一个数 \(A[x]\) 其能到达某一位有 \(1\) 的最前面的数的位置即可。最后判断 \(A[y]\) 的某一位 \(1\) 是否能被 \(A[x]\) 在其之前到达。复杂度 \(\mathcal O(n\log^2 n)\) 。

1168 D. Anagram Paths

有一棵二叉树,每条边上有小写字母或者 \('?'\) ,每次修改一条边上的字符,要求维护所有叶子到根的路径上的 \('?'\) 填为任意小写字母后是否能重排达到一致, 如果可以,还需输出每种字符的最大可能出现次数。

? 首先如果所有叶子深度不相等,无论怎么更改边上的字符都是无解。

? 然后令 \(f[x][c]\) 表示所有 \(x\) 子树内的叶子到 \(x\) 的路径上字符 \(c\) 的数量最大值,\(len[x]\) 表示 \(x\) 到叶子的距离。

我们可以归纳证明,能够重排达到一致当且仅当

?
\[
\forall x \sum_{c} f[x][c]\leq len[x]
\]
? 考虑当 \(x\) 是叶子时候,显然充要。对于任意非叶子节点 \(x\),假设其子树内所有点都满足条件,此时必要性显然。充分性考虑先将原先的所有路径排好,对于新加进来的边,如果是一条,则必然合法。如果是两条边,要满足式子必须改变的 \(f[x][c]\) 数量 \(<2\) ,此时另一边会有多出来的问号填上这个字符。

? 直接暴力维护 \(f[x][c]\) 复杂度是 \(O(nq)\) 的,但是之前的证明启发我们,对于只有一个孩子的节点,可以直接将该节点与孩子合并不影响答案。然后这里有一个二叉树的小套路,如果这样合并,二叉树的深度不超过 \(\mathcal O(\sqrt n)\) 。

? 证明,如果二叉树不存在只有一个儿子的节点,那么第 \(i\) 层的深度一定要大于第 \(i-1\) 层的深度,此时深度最多为 \(\mathcal O(\sqrt n)\) ,这样直接暴力修改 \(dp\) 值即可,复杂度 \(\mathcal O(q\sqrt n)\)。当然直接动态 \(dp\) 也是可以的。

1188 D. Make Equal

有一个序列 \(a\) ,每次可以花费 \(1\) 的代价将其中一个数加上 \(2\) 的幂次,求将所有数变成相等的数时所需的最少代价。

? 先将 \(a\) 从小到大排序,若我们将 \(a_n\) 最终加上了 \(S\) ,则 \(a_i\) 最终加上了 \(S+a_n-a_i\) 。那么问题转化为选择一个数 \(S\) ,最小化 \(\sum_{i=1}^n bit(S+a_n-a_i)\) 。

? 考虑按位 \(dp\) 决策 \(S\) 的每一位选 \(0\) 还是选 \(1\) ,因为最终要处理的贡献是等于 \(a_n-a_i, S\) 这一位数相加以及上一位的进位决定的,我们还需要记录哪些数在当前状态下被进位了。可以发现,假设考虑到了前 \(k\) 位,当前位会进位的数一定是按照 \(\mod 2^k\) 排序结果下的一个后缀,\(dp\) 的时候记录一下这个后缀的长度即可,复杂度 \(\mathcal O (n\log n)\) 。

原文地址:https://www.cnblogs.com/mangoyang/p/11482903.html

时间: 2024-10-31 06:34:09

Codeforces VP/补题小记 (持续填坑)的相关文章

codeforces 984补题

codeforces 984a 1 #include<bits/stdc++.h> 2 using namespace std; 3 int n; 4 int num[1010]; 5 int main(){ 6 scanf("%d",&n); 7 for(int i=1;i<=n;i++) scanf("%d",&num[i]); 8 sort(num+1,num+n+1); 9 if(n%2==1) printf("%

codeforces打完补题

https://codeforces.com/contest/1234/problem/D 写了个巨蠢的线段树(不愧是垃圾),有必要提醒下自己这种题怎么做 #include<iostream> #include<cstdio> #include<string> #include<set> #include<algorithm> using namespace std; const int maxn = 32; set<int> st[

Codeforces 802 补题

A 水题 同B #include<cstdio> #include<cstdlib> #include<cstring> using namespace std; const int maxn=1000000; int n,k,a[maxn],num; bool ex[maxn],need[maxn]; int main() {//freopen("t.txt","r",stdin); scanf("%d%d"

Educational Codeforces Round 24 CF 818 A-G 补题

6月快要结束了 期末也过去大半了 马上就是大三狗了 取消了小学期后20周的学期真心长, 看着各种北方的学校都放假嗨皮了,我们这个在北回归线的学校,还在忍受酷暑. 过年的时候下定决心要拿块ACM的牌子,一直坚持刷题,这一个学期刷了200道吧,感觉还是小有收获.特别是Ural和Codeforces上的题,质量很高. 然后4月的校赛,5月的省赛,发挥的也一般,不过也没有太失常. 希望暑假的选拔赛能碰到有趣的队友 蛤蛤. 这两天各种考试,实在是太忙,看了一下edu24的题目,不是很容易,做了一道水题,以

Educational Codeforces Round 74 (Rated for Div. 2)补题

慢慢来. 题目册 题目 A B C D E F G 状态 √ √ √ √ × ? ? //√,×,? 想法 A. Prime Subtraction res tp A 题意:给定\(x,y(x>y)\),问能否将\(x-y\)拆成任意多个质数之和 1.任意大于\(1\)的整数\(k\)都可以用\(2\)与\(3\)的线性表示 证: 若\(k\)是偶数,显然: 若\(k\)是奇数,则\(k\)可以表示成\(k = 3 + 2*k'\),显然: 毕. #include<bits/stdc++.h&

Codeforces Round #634 (Div. 3) 补题

A. Candies and Two Sisters 签到题,直接输出即可 代码 #include<bits/stdc++.h> #define INF 0x3f3f3f3f typedef long long ll; using namespace std; inline void read(int &p) { p=0;int flag=1;char c=getchar(); while(!isdigit(c)) {if(c=='-') flag=-1;c=getchar();} w

H5填坑笔记--持续更新

最近一直在做移动端的页面,发现很多的坑,这里做一下总结,填填坑…… css常见的问题(一) 一.iOS键盘首字母自动大写 IOS的机子,默认英文输入法状态下,首字母是自动大写的,有时候挺烦人的. 在iOS中,默认情况下键盘是开启首字母大写的功能的,如果业务不想出现首字母大写,可以这样: <input type="text" autocapitalize="off" /> 二.iOS输入框默认内阴影和样式问题 在iOS上,输入框默认有内部阴影,但无法使用

LCT 填坑系列

清华冬令营 T1用了LCT 这个东西以前有写过 然而并不熟练 发现没了板子根本就不会写 只能填一填坑辣 BZOJ 2843 LCT 1 #include <bits/stdc++.h> 2 #define N 30010 3 #define ls c[x][0] 4 #define rs c[x][1] 5 using namespace std; 6 7 inline int read() 8 { 9 int x=0,f=1; char ch=getchar(); 10 while(ch&l

2018-2019赛季多校联合新生训练赛第六场(2018/12/15)补题题解

A 价钱统计(基础编程能力) 这个考点还是比较个性的,怎么四舍五入 解法 常规的讲如果四舍五入整数位的话,那么只需要在后面加个0.5然后强制转换一下就可以了 这个却要我们保留一位小数的四舍五入,那该怎么做呢 实际上我们只需要把这个数乘以10然后加0.5,强制转换后再除以10就可以了 代码 #include <bits/stdc++.h> using namespace std; double trans(double a) { a*=10; a+=0.5; a=int(a); a/=10; r