DP技巧与DP杂题

DP常用技巧

  1. 增加维数
  2. 交换答案与状态
  3. 可行解转最优解
  4. 删掉本质相同的状态
  5. 对部分状态\(dp\)
  6. 遇到转移顺序的困难,考虑记忆化搜索
  7. 遇到转移细节过多的问题,考虑从 \(i\rightarrow i+1\) 而不是 \(i-1\rightarrow i\)
  8. 考虑状态时,先把需要记下来的都记一遍,再考虑优化

DP杂题

CF837D (可行性转最优化)

题目

我们把一个数的 roundness 值定义为它末尾 \(0\) 的个数。

给你一个长度为 \(n\) 的数列,要求你从中选出 \(k\) 个数,使得这些选出的
数的积的 roundness 值最大。

\(n\ge 200\)

题解

考虑一个很暴力状态,设\(f[i][j][a][b]\)表示考虑到第\(i\)个数,选了\(j\)个,因子\(2\)\(5\)的个数分别是\(a,b\)的方案是否存在,答案就是对\(f[i][k][a][b]=true\)的状态取\(\min(a,b)\)

我们发现直接这样转移的复杂度是\(\mathcal O(n^4)\)的,无法通过本题。

所以我们考虑套路可行解转最优解,设\(f[i][j][a]\)表示考虑到第\(i\)个数,选了\(j\)个,因子\(2\)个数为\(a\)时因子\(5\)最多是多少

这样子复杂度就降为了\(\mathcal O(n^3)\),可以通过本题

CF677D (分层图dp)

题目

有一个 \(n\times mn×m\) 的矩阵 \(a(1\le a_{i,j}\le p)\) ,求从起点 \((1,1)\) 出发依次遍历值为 \(1\to p\) 的矩阵单元的最短路径曼哈顿距离。保证满足 \(a_{i,j}=p\)\((i,j)\) 唯一。

数据范围:\(1\le n,m\le 300,1\le p\le n\cdot m\)
题解

我们先把数按照种类分组,分成 \(p\) 组。

\(f[i][j]\) 表示到达目前这个数的最短路,那么转移方程为 \(f[i][j] = \min\lbrace f[x][y]+|x-i|+|y-j|\rbrace\),其中 \((x,y)\) 为上一组中所有数的坐标。

然后要是直接暴力的状态转移的话,是要TLE的,考虑进行优化(下面这个优化真的太神仙了)。

考虑一个界限 \(K\),假设当前组为 \(\text{T}[i]\),上一组为 \(\text{T}[i-1]\)

那么当 \(\text{T}[i].\text{size} \le K\) 时,我们就用继续用上面的暴力动态转移,那么对于所有的“上一组”点数加起来不会差过 \(nm\),因此总时间复杂度 \(\mathcal O(K \cdot nm)\)

如果 \(\text{T}[i].\text{size} > K\),我们在网格上进行多源点的优先队列BFS,源点是所有的 \(\text{T}[i-1]\) 组内的点,搜出到所有 \(\text{T}[i]\) 组内的点的最短距离,这样BFS最多跑一遍所有网格,时间复杂度 \(\mathcal O(nm \log(nm))\);由于这样的组数目不会超过 \(\frac{nm}{K}\) 个,所以总时间复杂度为 \(\mathcal O(\frac{nm}{K} nm \log(nm) )\)

这样一来,两种加起来的总时间复杂度就是 \(\mathcal O(Knm+\frac{nm}{K}nm\log(nm) ) = \mathcal O( nm (K + \frac{nm\log(nm)}{K}) )\),由此可知取 \(K=\sqrt{nm \log(nm) }\) 时,时间复杂度最小,为 \(\mathcal O(nm\sqrt{nm\log(nm)})\)

P1004 [NOIP2000 提高组] 方格取数(去除冗余状态)

题意

给定一个 \(n\times m (n,m\le 200)\) 的矩阵,每个格子里有不同的正整数。一个人从左上角走到右下角,走两次,取走两次路径上的数(同一个数不可以重复取),最大化这些数的和

题解

显然我们可以设 \(f[i][j][k][l]\) 表示第一次走到 \((i,j)\) ,第二次走到 \((k,l)\) 时的最大值

考虑如何优化

首先,两次走的总步数一定是 \(n+m\) 的,同理,如果我们控制两次同时走的话,那么有 \(i+j=k+l\) ,这样我们就可以设 \(s=i+j\) 省下一维,转移方程很显然,注意两次相遇的问题即可

BZOJ 1801 中国象棋(DP) (去除不必要的维度)

题目

\(n\times m\)的棋盘上放若干炮使得不互相攻击。有多少种放法?

说人话就是,不存在三炮共线的情况有多少种

\(n,m\ge 100\)

题解

首先,一个显然的想法是进行状压\(dp\),设\(f[i][s]\)表示考虑到第\(i\)行,\(s\)是一个三进制状态,存每一列都用了多少个炮,这样转移的复杂度是\(3\)的指数级的,显然无法通过

我们考虑一件事,就是假设前\(i\)行的炮都放完了,那么第\(i+1\)行的炮能放的方案数只与剩余了多少位置能放有关,我们并不需要知道这些炮具体放在了什么位置

所以我们可以设\(f[i][j][k]\)表示,考虑完前\(i\)行,有\(j\)列还可以放\(1\)个炮,\(k\)列还可以放\(2\)个炮的总方案数

我们考虑转移

  • 放0个炮,那么就是:

\[  f[i+1][j][k]\leftarrow f[i][j][k]; \]

  • 放1个,可以放在还可以放1个炮的列中,也可以放在还可以放2个炮的列中:

\[\begin{aligned}   &if (j>=1) f[i+1][j-1][k]\leftarrow f[i][j][k]*j\\   &if (k>=1) f[i+1][j+1][k-1]\leftarrow f[i][j][k]*k \end{aligned} \]

  • 放2个,可以都放在还可以放1个炮的列中,也可以都放在还可以放2个炮的列中,也可以每边放一个:

\[\begin{aligned}   &if (j>=2) f[i+1][j-2][k]\leftarrow f[i][j][k]*(j*(j-1)/2)\\   &if (k>=2) f[i+1][j+2][k-2]\leftarrow f[i][j][k]*(k*(k-1)/2)\\   &if (j>=1 \And k>=1) f[i+1][j][k-1]\leftarrow f[i][j][k]*j*k \end{aligned} \]

[SCOI2008]着色方案 (利用题目性质优化状态)

题目

\(n\) 个木块排成一行,从左到右依次编号为 \(1\)\(n\)

你有 \(k\) 种颜色的油漆,第 \(i\) 种颜色的油漆足够涂 \(c_i\) 个木块。
且保证 \(\sum_{i=1}^kc_i=n\)

统计任意两个相邻木块颜色不同的着色方案

题解

一个变态朴素的想法,我们进行\(15+2\)维的\(dp\),那\(15\)维状态存对应的颜色剩余的个数,但是显然\(5^{15}\)实在无法令人接受

我们意识到一个问题,使相邻木块颜色不同并不需要枚举每一种颜色,事实上,我们只要保证当前颜色不与上一次的颜色相同,那么就是合法的转移,所以我们考虑优化状态

\(f[i][j][a][b][c][d][e]\)表示考虑到第\(i\)位,上一次选的数还剩\(j\)次可选,剩余\(1,2,3,4,5\)次的数分别还有\(a,b,c,d,e\)个,我们上一次选的这时候我们的状态数就为\(15^{5}\),这比上面那个东西小多了,复杂度是正确的

我们不能选的状态,就是剩余次数为\(j\)的颜色其中一个,直接转移就行

[AGC044A] Pay to Win (记忆化搜索,大力出奇迹)

题目

你需要通过如下操作把 \(0\) 变成 \(N\) \((N \le 10^{18})\)

  • \(\text{A}\) 个金币把数字乘 \(2\)
  • \(\text{B}\) 个金币把数字乘 \(3\)
  • \(\text{C}\) 个金币把数字乘 \(5\)
  • \(\text{D}\) 个金币把数字加一或减一。

求最少需要花费的金币。

题解

倒着记忆化搜索,乘法变成除法,遇到除不尽的通过加法调整

这样形成的就是一个深度为 \(\log N\) 的六叉树

时间复杂度 \(\mathcal O(\text{能过})\)

[USACO2.3]奶牛家谱 Cow Pedigrees (恰好到不超过)

题目

一个有 \(n\) 个节点,深度为 \(k\) 的无标号完满二叉树(即每个节点的儿子数为 \(0\)\(2\))有多少种结构?定义根节点深度为 \(1\)

答案对 \(9901\) 取模。

\(3\le n < 200\)\(2 \le k < 100\)

题解

考虑到 \(\text{恰好k个}\) 并不好做,所以我们考虑 \(\text{不超过k个}\) 怎么做

\(f[i][j]\) 表示点数为 \(i\) ,最大深度不超过 \(j\) 的二叉树的个数

枚举其左儿子大小进行转移即可

复杂度 \(\mathcal O(n^2k)\)

ZR2022 NOIP十连测Day6 T1 跳棋(有向图+tarjan缩点+拓扑排序/记忆化搜索的一类经典套路)

sb出题人卡常数,下面这个做法过不了

题目

在一个无穷大的跳棋棋盘上,放有 \(n\) 个棋子,第 \(i\) 个棋子的坐标为 \((x_i,y_i)\) ,问当前局面下各个棋子分别能够到达多少个位置

题解

考虑将每个棋子的答案分成两部分

  • 周围六格中没有放棋子的部分

    \(\text{map}\) 记一下各个棋子的位置,然后枚举就行, \(\mathcal O(n)\)

  • 连续跳跃的部分

    首先连续跳能够跳到的格子一定不超过 \(6n\) 个,因此能跳的位置连上有向边,边数也是 \(\mathcal O(n)\) 级别的

    然后用 \(\text{tarjan}\) 给有向图缩点,跑拓扑排序或者记忆化搜索得到答案

P7516 [省选联考 2021 A/B 卷] 图函数 (Floyd最短路dp)

PS:因为最短路算法和dp有着千丝万缕的联系,所以我在这里放几道偏图论的题应该问题不大(逃

题目

题解

第一步,拆贡献,我们直接计算每个点对 \(h(G)\) 的贡献

我们考虑一个问题,两个点可以相互到达,就说明了这两个点不在同一个强连通分量中,那么对于点 \(u\) ,我们考虑完前 \(x-1\) 个点之后,后面的图上的点都没有办法走到这 \(x-1\) 个点,因为前 \(x-1\) 个点已然不在强连通分量中,没有必要管了。

那么现在问题转化为,对于前 \(n\) 个图 \(G_1\sim G_n\) 分别求出有多少个点对 \((u,v),u\ge v\) 满足存在不经过 \(< v\) 的点使得两点可以互达

一个点对会对答案的前缀产生贡献,为了使答案最大化,我们贪心地考虑每个点对都通过一条使得其最小编号点最大的路径,差分一下处理即可

那么怎么求解两点间经过的最小编号点呢?仔细一想,这很符合 \(\text{Floyd}\) 算法的转移过程,所以使用 \(\text{Floyd}\) 求解即可

时间复杂度 \(\mathcal O(n^3+m)\) 勉强能冲

P3953 [NOIP2017 提高组] 逛公园 (分层图和spfa最短路dp)

题意

给你一张 \(n\) 个点 \(m\) 条边的有向图,起点为 \(1\) ,终点为 \(n\) ,边有非负边权(可以为 \(0\) )。求解使得 \(\text{dis}(1,n)\le \min\text{{dis}}(1,n)+K\) 的路径数

\(n\le 1\times 10^5,m\le 2\times 10^5,K\le 50\)

题解

神仙题!

由于 \(k\) 值很小,所以考虑建立分层图,设 \(f[i][j]\) 表示 \(\text{dis}(1,i)= \min\text{{dis}}(1,i)+j\) 的方案数,对于一条边 \((u,v,w)\) 转移为

\[f[u][j]\rightarrow f[v][\text{dis}_u+j+w-\text{dis}_v] \]

其中 \(\text{dis}_u\) 代表的是从 \(1\)\(u\) 的最短路

但是,我们发现这个转移在 \(0\) 环的情况下是错误的,若 \(0\) 环出现在最短路图上,则直接导致无解。于是考虑一件事,最短路图在无 \(0\) 环的情况下是个 \(\text{DAG}\) ,因此我们可以对最短路图进行拓扑排序判环,有环则当前层无解,否则拿记忆化搜索直接跑(不用考虑转移顺序多是一件美事),时间复杂度 \(\mathcal O(mk)\)

P7077 [CSP-S2020] 函数调用(DAG建模+dp)

题目

题解

首先考虑一个性质,如果只存在 \(1\) 操作,那么直接做就行,所以考虑如何将 \(2,3\) 两个操作转化成 \(1\) 操作

关键点在于:

  1. 某个函数被调用后序列被乘k,等价于这个函数被执行k次
  2. 乘法可以使用乘法标记

然后拓扑排序dp处理处理即可

P7962 [NOIP2021] 方差 (差分套路+dp)

题目

给定长度为 \(n\) 的非严格递增正整数数列 \(1 \le a_1 \le a_2 \le \cdots \le a_n\)。每次可以进行的操作是:任意选择一个正整数 \(1 < i < n\),将 \(a_i\) 变为 \(a_{i - 1} + a_{i + 1} - a_i\)。求在若干次操作之后,该数列的方差最小值是多少。请输出最小值乘以 \(n^2\) 的结果

其中方差的定义为:数列中每个数与平均值的差的平方的平均值。更形式化地说,方差的定义为 \(D = \frac{1}{n} \sum_{i = 1}^{n} {(a_i - \bar a)}^2\),其中 \(\bar a = \frac{1}{n} \sum_{i = 1}^{n} a_i\)

\(1 \le n \le {10}^4\)\(1 \le a_i \le 600\)

题解

初看这个操作感觉很无厘头是吧?那么试着把它差分吧!

于是我们发现操作等价于交换原数列差分数组中的两个数

然后我们不喜欢那个丑到爆的方差定义,于是设 \(S=\sum_{i=1}^na_i\) ,转移就是

\[\begin{aligned} &n\sum_{i=1}^n(a_i-\frac 1nS)^2\\=&n\sum_{i=1}^na_i^2-(\sum_{i=1}^na_i)^2 \end{aligned} \]

还有给定的 \(a_i\) 是单调递增的,所以差分序列是恒大于 \(0\)

考虑如何得到最优答案,感性理解一下,答案序列应该是个单谷序列,证明可以考虑调整法,这里不赘述

先将 \(a_i\) 按差分数组排序,然后设 \(f[i][s]\) 表示考虑了前 \(i\) 个数,\(\sum a_i=s\) 时最小的 \(\sum a_i^2\) 是多少,分类讨论当前数应该放在前面还是后面,于是有

\[\begin{aligned} f[i-1][s]+(\sum_{j=1}^ib_j)^2 \rightarrow f[i][s+\sum_{j=1}^ib_j]\\f[i-1][s]+i\times b_i^2+2b_i \times s\rightarrow f[i][s+b_i\times i] \end{aligned} \]

时间复杂度 \(\mathcal O(n^2a)\)

P7961 [NOIP2021] 数列 (跟二进制进位有关的dp)

题面

给定整数 \(n, m, k\),和一个长度为 \(m + 1\) 的正整数数组 \(v_0, v_1, \ldots, v_m\)

对于一个长度为 \(n\),下标从 \(1\) 开始且每个元素均不超过 \(m\) 的非负整数序列 \(\{a_i\}\),我们定义它的权值为 \(v_{a_1} \times v_{a_2} \times \cdots \times v_{a_n}\)

当这样的序列 \(\{a_i\}\) 满足整数 \(S = 2^{a_1} + 2^{a_2} + \cdots + 2^{a_n}\) 的二进制表示中 \(1\) 的个数不超过 \(k\) 时,我们认为 \(\{a_i\}\) 是一个合法序列。

计算所有合法序列 \(\{a_i\}\) 的权值和

\(1 \leq k \leq n \leq 30\)\(0 \leq m \leq 100\)\(1 \leq v_i < 998244353\)

题解

由于有进位的情况出现,因此考虑从低位向高位dp

\(f[i][j][k][l]\) 表示考虑到第 \(i\) 位,确定了 \(a\) 序列中的前 \(j\) 个元素,有 \(k\)\(1\),到下一位有 \(p\) 的进位,考虑给 \(S\) 的第 \(i\) 位贡献了 \(p\) 位,那么转移就为

\[f[i+1][j+p][k+(p+l)\% 2][\lfloor\frac{l+p}{2}\rfloor]\leftarrow f[i][j][k][l]\times v_i^p \times \binom{n-j}{p} \]

时间复杂度 \(\mathcal O(n^4m)\)

P6758 [BalticOI2013] Vim(线头dp)

原作者题解,这里引用一下LOJ2687 BalticOI2013 Vim 线头DP,因为原作者写的实在是太好了,所以这里建议去原作者博客获得更好的阅读体验,放这里是方便笔者自阅

题目

题解

原题等价于:给出一个序列和两种移动方式,移动过程中必须要经过某一些点,求最小代价。

把连续的f操作和连续的h操作看成线,那么移动路线如下

首先,考虑下面两种移动路线

显然A路线一定没有B路线优

上面的条件等价于对于某一个位置 \(i\),经过的位置覆盖了位置 \(i\)\(i+1\) 之间的线段的线的数量要么是 \(1\) ,要么是 \(3\) ,对应下图的 AB 两种情况。

\(p_{i,j}\) 表示覆盖了 \(i\)\(i+1\) 之间的线段 \(1\) 次,且 \(f\) 操作选择字符 \(j\) 的最小代价,\(q_{i,j,k}\) 表示覆盖了 \(i\)\(i+1\) 之间的线段 \(3\) 次,且在进行 \(h\) 操作之前的 \(f\) 操作选择的字符是 \(j\)、在进行 \(h\) 操作之后的 \(f\) 操作选择的字符是 \(k\) 的最小代价

又设 \(s_i\) 表示字符串的第 \(i\) 个字符,\(\text{imp}_i\) 表示原串中第 \(i\) 个字符前是否存在字符 \(e\)

转移:

\[\begin{aligned} p_{i,j} = & p_{i-1,j} & j \neq s_i \&\& \text{imp}_i \neq 1\\& p_{i-1,s_i} + 2 \\& q_{i-1,s_i,j} & j \neq s_i \\ & q_{i-1,s_i,s_i} + 2 \end{aligned} \]

\(p_{i,j}\) 的转移分别对应下图的ABCD情况

其中虚线表示新加入的线,红色字表示对应位置的字符类型,黑色字表示位置编号

\[\begin{aligned} q_{i,j,k} = & p_{i-1,j} + 3 & j \neq s_i \\ & p_{i-1,s_i}+5 \\ & q_{i-1,j,k} + 1 & j \neq s_i \&\& k \neq s_i \\ & q_{i-1,s_i,k} + 3 & k \neq s_i \\ & q_{i-1,j,s_i} + 3 & j \neq s_i \\ & q_{i-1,s_i,s_i} + 5 \end{aligned} \]

\(q_{i,j,k}\) 转移分别对应下图中的ABCDEF情况






转移就是把线延长和补全的过程,所以叫做线头DP

代码源省选班 字符串 (子段切分问题)

题面

给定一个长度为 \(n\) 的由 AB? 组成的字符串,求有多少种方式可以把每个 ? 替换为 A 或 B 后,字符串中,长度为 \(m\) 的连续全 A 或全 B 字串恰好有 \(k\) 个

题解

一种朴素的状态是: 设 \(f[i][j][p][c]\) 表示考虑到第 \(i\) 个数,当前有 \(j\) 个合法子串,已经有 \(p\) 个连续的字符 \(c\) 时的方案数,转移是 \(\mathcal O(n^3)\)

考虑优化,去掉 \(p\) 一维,每次不再填一个字符而是填一个极长连续段,这是这种子段切分问题的一个常见优化思路

那么就有转移

\[f[i][j][c]=\sum_{t=1}^\text{len} f[i-t][j-\max(0,k-t+1)][c'] \]

其中 \(\text{len}\) 表示以 \(i\) 为端点不包含 \(c'\) 的子串长

二维前缀和优化即可

时间复杂度 \(\mathcal O(n^2)\)

ZR2020 提高组十连测 day5 T3 (点边数差异不大时的一种处理图上dp的做法)

题意

过了一阵子的辉夜又开始想起了这件事,她开始在意起如果那时候她真的出去乱走,到底什么时候能回到这里呢?可以把街区抽象为一个连通的无向简单图 \(G=(V,E)\),这个楼梯在 1 号点,每到一个点 \(i\) ,辉夜都要休息 \(w_i\) 分钟(包括在 1 号点出发之前),多次到达一个点的话需要多次休息。离开一个点的时候,迷茫的辉夜会等概率选择任意一条与这个点相连的边走过去(假定走路不需要时间)。现在辉夜得到了地图,她想知道从楼梯( 1 号点)出发,第一次回到这里时的期望花费的时间(注意这包含了出发前的休息时间,但回到 1 号点后的休息时间不计入),你能告诉她吗?

题解

\(n,m\le 500\) 是图上随机游走的板子,高斯消元即可,时间复杂度 \(\mathcal O(m^3)\)

树的情况就考虑树形dp,设 \(f_i\) 表示从 \(i\) 出发走向 \(i\) 的子树,第一次走到 \(i\) 父亲的期望时间,转移就考虑它走到它儿子的概率,方程如下

\[f_u=w_u+\frac{1}{d_u}\sum_{v\in\text{son}_u}f_v \]

时间复杂度 \(\mathcal O(n+m)\),至此38pts

注意到 \(n-1\le m\le n+ 500\) ,感性理解一下,这表明原题中真正需要用到高斯消元的式子并不多。赛时想了一下边双缩点,但这显然没有什么用,出题人给出了一种很震撼的虚树做法

我们考虑先在原图中找出一棵 DFS 树,其中包含了 \(n-1\) 条边,接着我们依次遍历剩下的 \(m-n+1\) 条边,把每条边相邻的两个点都在 DFS 树上标记一下,作为关键点;接着,我们根据 DFS 树的连通关系,给我们标记出来的点建一棵树,我们求出这棵树的虚树(实际上是在补全lca,会多出来一些新的关键点),然后将关键点删掉,得到的新图有两个性质

  1. 我们就去掉了原图中所有的环

证明可以考虑反证法,假设删完后存在环,那么至少有一条边环边不在 DFS 树上,环上至少有两个关键点,关键点又被删掉了,出现矛盾

  1. 新图中任意一个连通块至多与两个关键点相邻

同样考虑反证法,假设存在连通块与大于两个关键点相邻,那么一定存在两个端点处的关键点有 lca,这个 lca 也是关键点并且还没有被删(被删了这几个关键点就分开了),出现矛盾

那么我们就可以对每一个连通块做树形dp,加回关键点的时候在虚树上做高消即可算出每个点的答案,时间复杂度 \(\mathcal O(m+(m-n)^3)\) ,按出题人的意思只能得 77pts

但是我们注意到,加边带来的至多 \(2(m-n)\) 个关键点再加上建虚树时作为 lca 的关键点 ,我们关键点的个数可以被卡到 \(3 (m-n)\) ,理论上无法通过此题,我不是很看的懂出题人下一步的优化是怎么做的,但是我用上面的做法加fread优化冲过去了

ZR2020 提高组十连测 Day10 T2 (树的拓扑序计数于dp中的应用)

题意

你有一个数列 \(A=(1)\),也就是一开始只有一个元素。

你要对这个数列进行 \(N\) 次操作,每次操作可以是下面的一种:

  1. \(A\) 数列的末尾加入 \(1\) 或者 \(M\)

  2. 选择一个下标i满足 \(1\leq i < |A|\),然后选择一个数字 \(x\) 满足 \(a_i< x < a_{i+1}\) 或者 \(a_i > x > a_{i+1}\),然后将数字插入到 \(a_i\)\(a_{i+1}\) 之间。

问有多少种不同的操作序列。这里两个操作序列不同,当且仅当存在某个时刻,使得操作完两个数组的内容不同。

\(1\leq N\leq 3000, 2\leq M\leq 10^8\)

题解

\(f_i\) 表示考虑到第 \(i\) 个操作形成了若干段时有多少种操作序列。如果该位置操作与上一段结尾相同,那么就不能插入别的数;否则就组合数计算方案数,而根据大小关系,我们可以给我们建出来的序列建出一棵树,操作顺序必须是这棵树的一个拓扑序。

而我们知道,有根树的拓扑序数量为

\[n!\prod_u\frac{1}{\text{siz}_u} \]

因而直接套树的拓扑序计数的套路,每次注意把新生成的子树大小给除上去就行了,时间复杂度 \(\mathcal O(n^2)\)

ZR2023 NOIP赛前20连测 Day5 T2 (根据所求缩小状态个数)

题意

小诗想生成一个长为 \(n\) 的序列 \(a\),她首先确定了每个位置取值的上下界 \([l_i,r_i]\),接下来对每个位置生成上下界内的任意正整数 \(a_i\in[l_i,r_i]\)。她会用以下方式评判 a 的权值:

取某一值域 \([1,n-3]\) 的可空子集 \(S\subseteq\{1,2,\cdots,n-3\}\),并计算 \(\prod_{x\in S}\gcd(a_x,a_{x+1},a_{x+2},a_{x+3})\)(在 \(S=\varnothing\) 时定义该式值为 \(1\)),并对所有子集的答案求和。

她想知道所有能生成的序列权值之和,由于答案过大,你只需告诉她答案对 \(10^9+7\) 取模后的结果。

对于所有测试点,\(4\leqslant n\leqslant 200,1\leqslant m\leqslant 100\)

题解

对于一个序列方案,它的权值即为

\[\prod_{x=1}^{n-3}(\gcd(a_{x},a_{x+1},a_{x+2},a_{x+3})+1) \]

然后考虑 dp ,最暴力的做法就是枚举三个值进行转移,时间复杂度是 \(\mathcal O(nm^4)\) 的,无法接受

考虑我们要求的是四个数的 \(\gcd\) ,所以对于相邻的三个数 \(a,b,c\) 我们只需记录 \(\gcd(a,b,c),\gcd(b,c),c\) ,他们三个之间呈倍数关系,因此状态总数来到了 \(\mathcal O(m\log m)\) 级别,总时间复杂度降为 \(\mathcal O(nm^2\log m)\)

posted on 2023-10-27 17:58  star_road_xyz  阅读(18)  评论(0编辑  收藏  举报

导航