首页 > 其他分享 >杭州集训 Day 3

杭州集训 Day 3

时间:2024-10-23 08:58:23浏览次数:1  
标签:表示 复杂度 集训 sum 可以 考虑 杭州 Day dp

课前

早饭 htdlz 帮忙买的,一碗粥和三个不知名的糕点,粥并不好喝,但是糕点好吃。

早上到了机房把这儿的小破电脑换成了自己的笔记本,屏幕大一点舒服一些。hs_black 走了,今天换 syksykccc 来讲,syk 开朗幽默的多,上课和机房这群很有话题。而且他甚至把他讲的每个题对应的代码打了,然后课后发了。

课前他自我介绍说:“我是高一拿的 Ag,后来觉的 OI 比 whk 难然后就 AFO 了,最后裸分考的北大。”

syk 还发表了一些逆天言论,如 “破链为环” 解决区间 dp 问题

笔记

P2051

设 \(f[i][j][k]\) 表示从左上角一直到坐标 \((i,j)\) 并且用了 \(1\)~\(k\) 个象棋的方案数

\(n\) 的数据范围很小,可以 \(n^3\) 暴力遍历

\(v[i][j]\) 标记棋子

但是转移并不好写,考虑找性质,发现对于每行每列炮的个数不会超过两个

所以将第二,三维优化

\(j\) 表示 有 \(j\) 个列是 \(1\) 个炮,\(k\) 表示有 \(k\) 个列放 \(2\) 个炮,剩下的放 \(0\) 个炮

转移的时候就考虑在当前行放 \(0 / 1 / 2\) 个炮,以及这些炮放在了之前有几个炮的列上

现在可以暴力转移,复杂度三次方级,可以通过

P1437

将原图形旋转变成左下角为直角的等腰直角三角形形式,那么想要拿走一个砖,就必须要拿走左边那个和左上角那个,考虑有依赖的背包 dp

显然的,可以将当前砖和左边那个和左上角那个绑定,他们的分值和为质量,个数为体积,然后背包

但是一定会有重复绑定导致计算错误,所以要考虑找特殊性质,发现第 \(i\) 行被打掉的一定是一个前缀,用 \(f(i, j, k)\) 表示当前考虑到第 \(i\) 行,这一行的轮廓线转折点在 \(j\),已经打了 \(k\) 个砖头的最大收益。

\[f(i,j,k) = \max_{l≥j-1} \{ f(i-1,k,k-j)+S_i(j) \} \]

复杂度 \(O(n^4)\)

P6189

显然可以平方级别的背包 dp,但是显然过不了。但是对于背包 dp 它也有两种不同的状态设计,

\(f(i, j)\) 表示把 \(i\) 拆成 \(≤j\) 的数的方案。\(g(i, j)\) 表示把 \(i\) 拆成 \(j\) 个数的方案。这个直接递推转移是非常好实现的。

之后根号分治,对于小于等于 \(\sqrt n\) 的数据计算 \(f\),剩下的计算 \(g\)(这里数据指的是 dp 第二维)

复杂度 \(O(n \sqrt n)\)

之后考虑如何使用 \(f,g\) 更新计算答案

\[\sum_{s=0}^n (f(s, M) \times \sum_{c=0}^Mg(n-s,c)) \]

\(M\) 指的是根号分界

P7962

将答案式子展开化简后为 \(n \sum_{i=1}^na_i^2 - (\sum_{i=1}^na_i)^2\)

对于一次操作,原来相邻两个数的差为 \(a_i - a_{i-1}\) 变为了 \(a_{i+1} - a_i\)。即一次操作是在交换差分数组的相邻两项,
可以任意交换差分数组得到一个新的差分排列。为了使所有数字趋于平均值,差分数组应当是单谷序列,微扰法可以证明。将差分数组 \(b\) 从小到大排序,然后依次考虑每一项,要么插在当前最左边,要么插在当前最右边。

令 \(a_0 = 0\),设 \(f(i,s)\) 表示考虑了前 \(i\) 个数,当前 \(∑a_i = s\)
的情况下,最小的 \(\sum a_i^2\) 是多少。

  • \(f(i,s+\sum_{j=1}^{i}b_j) = f(i-1,s)+(\sum_{j=1}^{i}b_j)^2\),放在右边

  • \(f(i,b_i*i+s)=f(i-1,s)+i*b_i^2+2*b_i*s\) ,放在右边

直接 dp 复杂度为 \(O(n^2a)\)

注意到差分数组中非 \(0\) 项至多 \(O(a)\) 个,而对于 \(b_i = 0\) 毕竟排在最前面,无论放左放右都是一样的,所以直接铺开就行了,于是时间复杂度就能做到 \(O(na^2)\)

P6764

计算出 \(P_i = 0/1\) 表示能否从 \(i\) 开始进行一次粉刷,之后的就是很平凡的贪心区间覆盖问题。

假设现在 \(|F_c| ≤ 1\),那么每个墙能指派的承包商是固定的。用 \(f(i)\) 表示从第 \(i\) 段墙开始最远能刷到哪里。

用 \(f(i, j)\) 表示从第 \(i\) 段墙开始,让承包商 \(j\) 来粉刷,最远能刷到哪里。可以 \(O(nm)\) 逆序递推。初始化 \(0xcf\),对于 \(j ∈ F_{c_i} ∧ (i = N − 1 ∨ (j + 1) \mod m ∉ F_{c_i}+1\) 的情况,\(f(i,j) = i\)。剩下的 \(j ∈ F_{c_i}\) 的情况 \(f(i + 1,(j + 1) \mod m)\)

然后还有一些优化的 trick 卡一下就过了

P5289

用 \(f(x, y)\) 这样的状态去做背包,表示考虑到当前学校的时候,红阵营有 \(x\) 人,\(A\) 派系有 \(y\) 个人的方案数。复杂度是 \(O(nM^2)\)

假如 \(k = 0\) 发现可以先计算阵营的分配方案数,再计算派系的方案数,然后把两个乘起来即可。这两个都是可以一维背包实现的,复杂度 \(O(nM+cM)\)

对没有限制的学校用分别 \(dp\) 的方式,对于有限制的学校,因为不超过 \(k\) 个,所以用二维 \(dp\) 的方式再合并一下答案,总复杂度 \(O((n + c)M+ k^2sM)\)

P4302

用 \(f(l,r)\) 表示 \(S[l · · ·r]\) 的答案。

  • 第一条:\(f(l,r) ← (r − l + 1)\)

  • 第三条:\(f(l,r) ← f(l, k) + f(k + 1,r)\)

  • 第二条:枚举循环节长度 \(k\),
    \(f(l,r) ← f(l, l + k − 1) + 2 + digits((r-l+1)/k)\)

枚举 \(k\) 是 \(r − l + 1\) 的因子的去检查,调和级数可得复杂度 \(O(n^3 \log n)\)

P6879

时间值域太大了,不好设计进状态,但是答案很小,考虑交换定义域和值域设计 dp 状态。

\(f(l,r, b_{lr}, k)\) 表示当前考虑了 \([l,r]\) 这一段的所有打卡点,
\(b_{lr}\) 表示终止时站在 \(l\) 还是 \(r\),真正成功打卡了 \(k\) 个点时,最小花费的时间。用每一个已经求出的 \(f(l,r, b_{lr}, k)\) 的状态去更新 \(f(l − 1,r, *, *)\) 和 \(f(l,r + 1, *, *)\)。\(k\) 是否要增加可以根据两个 \(b\) 的值很方便地计算。

那么初始时把所有的状态都赋值为无穷,如果一个状态的最小时间不是无穷就说明有意义,用它去刷表。最后要查看有意义的状态的 \(k\) 的最大值。

复杂度 \(O(n^3)\)

P1864

不能修改数据值,所以这棵树的中序遍历固定。另一点是,由于可以修改为任意实数,实数是可以无限接近但是不相等的,所以完全可以理解为,允许权重相同,并且权重相同的点可以以任何你想要的顺序排序。即允许假定权重是整数来考虑这个问题。用 \(f(l,r, k)\) 表示把 \([l,r]\) 建树并且保证子树内所有点的权重都 \(≥ k\) 的时候,最小化的答案。\(f(l,r, k)\) 通过枚举根节点 \(t\),分别考虑不需要 /需要修改,利用下两式来更新

\[f(l, t − 1, w_t) + f(t + 1,r, w_t) +∑_{i=1}^r freq_i (w_t ≥ k) \]

\[f(l,t-1,k) + f(t+1,r,k)+K+\sum_{i=1}^r freq_i \]

其中 \(∑freq_i\) 表示深度 \(+1\) 之后代价的增量。总复杂度为 \(O(n^4)\)

P7605

设 \(f(l,r)\) 为答案

转移 \(f(l,r)\) 考虑第一步选择了左边还是右边,不妨设左边。

如果最终都没消去,那么就是 \(f(l + 1,r) + (1, 1)\)

如果最终利用 \(c_k\) 消去了,考虑一下 \(c_k\) 是从左端取出的还是
从右端取出的。

不妨设是右端取出的,那么显然 \([k + 1,r]\) 要先被删除,考虑
枚举 \(j\) 表示 \([l + 1, j]\) 辅助了这一段的删除,那么转化后的子
区间就是 \([j + 1, k − 1]\)

用 \(\max\{f(j + 1, k − 1),2, 1 + g(l + 1, j, k + 1,r)\}\) 来表示这个转移

其中 \(g(l_1,r_1, l_2,r_2)\) 表示完全消除 \([l_1,r_1] ∪ [l_2,r_2]\) 所需要的栈的大小。当然也有可能为无穷,此时对应的状态不能用来转移

关于 \(g\) 的转移,考虑是先取出 \(l_1\) 还是 \(r_2\)。

比如是 \(l_1\),考虑它和哪个位置配对,比如是和 \(c_i\),其中 \(i ∈ [l_2,r_2]\)。再枚举左侧辅助消除 \([i + 1,r_2]\) 的区间是 \([l_1 + 1, j]\),那么转移就可以表示为 \(\max\{g(l_1 + 1, j, i + 1, r_2) + 1, g(j + 1,r_1, l_2, i-1)\}\)

理论复杂度 \(O(n^6)\) ,实际上可以快速判断一些 \(g\) 的值为无穷,比如区间长度和是否为偶数,区间内的数是否两两配对(可以哈希之后求异或
和)。这样常数很小。可以用记忆化搜索实现。

P7077

如果没有第 \(2\) 类,考虑计算每个第 \(1\) 类函数的实际被调用次数。

第 \(2\) 类函数可以看作,对原始数据的乘法 + 将之前的第 \(1\) 类函数调用 \(V_i\) 次。

建立一个 \(DAG\),每个第 \(3\) 类函数(可以把 \(f_1, · · · , f_Q\) 也建模成一个第 \(3\) 类函数)向它所调用的所有函数依次连边。

首先考虑计算原始数据的贡献,这个只需要一次 dp 求出每个函数调用造成的全局乘积大小,然后就可以方便的计算总倍率。

逆序第 \(3\) 类函数序列。动态维护一个乘积 \(prod\) 表示当前子函数需要执行多少次。每遇到一个子函数,就在它对应的节点上打 \(+prod\) 标记,然后再更新 \(prod\)。这样便可以拓扑排序后利用 dp 求出每个函数需要调用的次数,累加贡献。

复杂度 \(O(n + \sum C_i)\)

P4577

每个节点开一个 multiset \(f_u\),从大到小的第 \(x\) 个数,表示当答案为 \(x\) 时的最大转移权值。

首先不考虑 \(u\) 的话,\(f_u =∪f_v\)

考虑 \(u\),那么把 \(w_u\) 插入 \(f_u\),然后除非 \(w_u\) 是 \(f_u\) 中最小的,否则把 \(w_u\) 的前一个 iterator 删除。合并 \(f\) 时可以使用启发式合并,复杂度 \(O(n \log^2 n)\),如果使用权值线段树维护可以做到单 \(\log\)

P5024

设 \(f(u, 0/1)\) 表示 \(u\) 的子树,\(u\) 不选 / 选,从“转移模式”来
看,除了 \(a, b\),其他的点依然在做相同的操作。

首先一次 \(dp\) 求出前文提到的 \(f(u, 0/1)\) 数组,现在考虑把 \(f\) 倍增化。用 \(g(u, k, 0/1, 0/1)\) 表示对于 \(u\),它选不选,它的 \(2^k\) 级父亲 \(fa\) 选不选,则 \(tree(fa) − tree(u)\) 的最优代价。初始化为

\[g(u, 0, 0, 0) = inf \]

\[g(u, 0, 1, 0) = f(fa, 0) − f(u, 1) \]

\[g(u, 0, 0/1, 1) = f(fa, 1) − min(f(u, 0), f(u, 1)) \]

倍增转移时枚举 \(2^{k−1}\) 级父亲的状态

现在分两种情况讨论询问。如果 \(a, b\) 是祖先-后代关系,那么,先用 \(b\) 的 \(f\) 去初始化状态 \(res_0,res_1\),分别表示当前的根节点是不选/选的最小代价。然后用 \(g\) 去倍增到 \(a\),再把 \(res_x\) 赋值为 \(0\),最后一路倍增到根节点即可。如果不是的话,同理,分别从 \(a, b\) 用上面的操作倍增到 LCA 下方的节点,然后在 LCA 处暴力合并答案,再倍增到根节点即可。复杂度只有一个 \(\log\)

课后

绝区零常驻池第一个常五是狼哥,第二个十连出了苍角,抽那个小不点不知道是什么的东西上来十连出了一个金,后来换成鲨什么蓝色的那只十连又出了。

暗示我抽鲨鱼妹

但是我 50 抽了还没出,运气太差

傻鸟米哈游不如洛谷好玩

标签:表示,复杂度,集训,sum,可以,考虑,杭州,Day,dp
From: https://www.cnblogs.com/spaceswalker/p/18494373

相关文章

  • C++入门Day5 ~ 6:简单变量 & 数据类型 part 1 <8000字长文带你初步理解数据类型>
    这是我在学习中的一个小问题,希望对你也有所帮助:        问:数据类型和简单变量属于oop的基本概念吗?        答:不是!数据类型和简单变量本身并不属于面向对象编程(OOP)的基本概念,但它们是编程中的基础概念,面向对象编程会基于这些基础概念来构建更复杂的结构。......
  • 代码随想录算法训练营day22和day23 | 77. 组合 216.组合总和III 17.电话号码的字母
    学习资料:https://programmercarl.com/回溯算法理论基础.html回溯法backtracking:for循环控制递归数量,暴力搜索:组合、切割、子集、排列、棋盘今天学了组合和切割可以画个N叉树的图来帮助理解回溯过程组合又包括1.单个数组(要加startIndex参数)或多个数组;2.数组内有无重复元素;3.数......
  • Day22--下标越界及小结
    Day22--下标越界及小结数组的四个基本特点:长度是确定的,一旦被创建,大小不可改变。元素必须是相同类型,不允许混合类型。元素可以是任何数据类型,包括基本类型和引用类型。在Java中,数组对象在堆中。数组边界数组边界特点如下:下标的合法区间为[0,length-1],如果越界就......
  • NOIP2024集训Day58 字符串
    NOIP2024集训Day58字符串C.[CEOI2011]Matching发现要做的是排名串的匹配。考虑把它转成这个位置之前有多少个数小于当前这个数,这样就只要每个位置都对应相等的,那就一定是合法的。然后就可以类似KMP的预处理出一个\(nxt\)数组,然后再类似KMP的匹配。因为需要支持动态......
  • P2866 [USACO06NOV] Bad Hair Day S
    [USACO06NOV]BadHairDayS题目描述农夫约翰有NNN头奶牛正在过乱头发节。每一头牛都站在同一排面朝右,它们被从左到右依次编号为......
  • 「Day-4 提高笔记-LCA最近公共祖先」
    #include<iostream>usingnamespacestd;constintMAXN=5*1e5+5;structnode{ intto,next;}e[MAXN*2];intf[MAXN][20],dp[MAXN];//f[x][i]表示x的第2^i个节点的编号inth[MAXN*2],tot=0;intn,m,s;voidadd(intx,inty){ e[++tot]={y,h[x]}; h......
  • CSP2024 前集训:多校A层冲刺NOIP2024模拟赛11
    前言T1不知道啥是冒泡排序,理解了一会儿题面代码发现是啥意思了于是就签了。后面的题都不是很可做,T2、T4计数,T3高级玩意看不懂。但是T2有点可做,但我的DP不知道哪儿假了,暴力还打挂了,不然加个bitset就操过去了。T1冒泡排序\(i\)只能和\(i+k,i+2k,……\)换,对于每一......
  • Day22--内存分析
    Day22--内存分析Java内存分析:1.堆:存放new的对象和数组;可以被所有的线程共享:不会存放别的对象引用2.栈存放基本变量类型(会包含这个基本类型的具体数值)引用对象的变量(会存放这个引用在堆里面的具体地址)3.方法区可以被所有的线程共享包含了所有的class和static变量......
  • 代码随想录算法训练营Day42 | 完全背包理论基础、518.零钱兑换II、377. 组合总和 Ⅳ、
    目录完全背包理论基础518.零钱兑换II377.组合总和Ⅳ卡玛网57.爬楼梯(进阶版)完全背包理论基础题目52.携带研究材料(第七期模拟笔试)题目描述:小明是一位科学家,他需要参加一场重要的国际科学大会,以展示自己的最新研究成果。他需要带一些研究材料,但是他的行李箱空间......
  • 二叉树习题其三-Java【力扣】【算法学习day.10】
    前言书接上篇文章二叉树习题其二,这篇文章我们将基础拓展###我做这类文档一个重要的目的还是给正在学习的大家提供方向(例如想要掌握基础用法,该刷哪些题?)我的解析也不会做的非常详细,只会提供思路和一些关键点,力扣上的大佬们的题解质量是非常非常高滴!!!习题1.从中序与后序遍历序......