DP小小结

入门题 : [Luogu1441]砝码称重 , [NOIP2015]子串

[AHOI2009]中国象棋 , 详见代码

[HNOI2007]梦幻岛宝珠 , 详见代码

[NOIP2012]开车旅行 , 没有代码...

预处理出\(ga[i] , gb[i]\)代表从城市\(i\)出发\(A\)\(B\)走一步会到达的城市
\(f[i][j][k]\)表示从城市\(j\)出发 , 两人共驾驶\(2^i\)天 , \(k\)先开车 , 最终会到达的城市
\(da[i][j][k]\)表示从城市\(j\)出发 , 两人共驾驶\(2^i\)天 , \(k\)先开车 , 小\(A\)的行驶路程总长度
\(db[i][j][k]\)表示从城市\(j\)出发 , 两人共驾驶\(2^i\)天 , \(k\)先开车 , 小\(B\)的行驶路程总长度

注意转移是有\(f[1][j][k]\)的情况 , 此时由于天数\(2^0\)是奇数 , 前后开车的人不一样 ; \(i>1\)以后开车的人就一样了.
\(calc(s,x)\)表示计算从\(s\)城市出发最多走\(x\)公里A和B分别行驶了多长路程.
这三个状态都可以做到\(O(n\log n)\)预处理 , 只有一个\(1\)询问 , 就直接对每一个点都求一次求最小值 ; 对于\(2\)询问就直接\(alc(s,x)\)

倍增\(DP\)基础 : [Luogu5151]HKE与他的小朋友 , 题解是这样说的 , 我的解释
还有这个 : [Luogu1613]跑路

每个状态都有一个对应的后继状态 , 这样的题可以用倍增处理 .
一开始觉得这道题非常不可做 , 因为它的转移一定是要枚举的 , 学到后面才发现很多东西都可以预处理出来 , \(DP\)也就是这个道理
\(DP\)对状态的最优化就是倍增了 .

[NOIP2015]斗地主 , 详见代码

神仙贪心 ,优秀的DP

\(dp[i][j][k][l][z]\)为有\(i\)\(1\)张牌 , \(j\)种 2 张牌 , \(k\)\(3\)张牌 , \(l\)\(4\)张牌 , \(z\)张王的出牌次数

写出各种转移方程 , 注意循环的次序 , 等式右边一定要比左边先循环到

[NOI2009]管道取珠 , 详见代码

方案数的平方和转化为选两次结果一样的方案数

\(f[i][j][k]\)表示第\(1\)种方案第一行选了\(i\)个 , 第二行选了\(j\)
第二种方案第一行选了\(k\)个 , 第二行选了\(i+j-k\)个 , 两次取出的球一样的方案数

[JXOI2018]游戏

首先计算出\(l\)\(r\)中,不是任何数的倍数的有多少个,记这个值为\(sum\)。比如说\(l=4,r=8\)时,\(4,5,6,7\)都不是任何数的倍数,此时\(sum=4\)。我们称这样的数为“关键数”

不难发现,\(t(p)\)的定义,其实就是排列\(p\)中,最后一个关键数的位置

于是我们可以枚举最后一个关键数的位置\(i\),在它后面不能存在关键数,所以它后面的元素有\(C(n-sum,n-i)\)种选取方法,对于每种选取方案,\(i\)后面的元素有\((n-i)!\)种排列方式,\(i\)前面的元素有\((i-1)!\)种排列方式,然后\(i\)这个位置可以是\(sum\)个关键数中的任意一个,并且这个位置对答案的贡献为\(i\)
于是答案可以表达成下式:

$\sum\limits_{i=1}^ni\times sum\times \binom{n-sum}{n-i}\times(n-i)!\times(i-1)! $

直接预处理阶乘及其逆元即可,\(sum\)直接埃氏筛\(O(n*l_nn)\)暴算即可

关于倍数的题目,枚举最小的"关键数"是很巧妙的套路.

[FJOI2016]建筑师

注意到建筑高度不同且取满\([1,n]\)
把所有的建筑分成 \(A+B-1\) 个部分 , \(n\)是最高点 , 把除了 \(n\) 以外的 \(n-1\)个建筑放到 \(A+B-2\)个圆桌上
相当于从高往低插入 , 可以选择独占一桌 , 即形成一个高峰 ; 或者补充到某一桌(块)某一人(楼)旁边 , 也就不会被看到
然后\(A+B-2\)个部分要选出\(A-1\)个放在左边 , \(B-1\)个放在右边

[51Nod1376] 最长递增子序列的数量 , 这个是完全看代码

树状数组也可以维护两个值 : 最大值和方案数

[USACO19FEB]Moorio Kart , 详见代码

\(O(n^2)\)暴力统计出每个森林的路径 , 从\(ctgn\)个集合中各选出一个数 , 使得长度\(>=Y\)的方案数 .

用背包统计 . 具体实现 :
\(dp[i+j][0]\leftarrow dp[i][0]*g[j][0]\)
\(dp[i+j][1]\leftarrow dp[i][0]*g[j][1] + dp[i][1]*g[j][0]\)

数据范围\((n^2)\)能做的事 : 以每个点为根遍历一遍算答案 . 正确性 : 以每一个点为一个端点来统计

[ZJOI2008]生日聚会 , 详见代码

\(n\)个男孩和\(m\)个女孩坐成一排,求任意一段区间内男孩和女孩的数量之差不超过\(K\)的方案数.

\(f[i][j][x][y]\)应该是前\(i\)个人中有\(j\)个是男生,以当前点为结尾的任意一段不超过\(k\)的区间男生比女生最多多\(x\)人,女生比男生最多多\(y\)人的方案数

设状态的时候注意,这一题中两维的状态根本无法描述全部情况,至少开第三维,然而还是不能解决问题,考虑到数据范围很小,就开到了第四维.

采用刷表法更方便.\(f[0][0][0][0]=1.\)

这样搞可以保证转移的合法性,最终统计答案的时候就直接把使用的\(f[n+m][m][i][j]\)加起来就可以了.

[HAOI2018]奇怪的背包 , 详见代码

\(F[i][j]\) 表示选到 \(P\) 的第 \(i\) 个约数,选出的数的 \(gcd\) 值为 \(P\) 的第 \(j\) 个约数的方案数
则有 \(F[i][j]=F[i−1][j]+(1+∑_{gcd(a[k],a[i])==a[j]}F[i−1][k])∗(2^{s[i]−1})\)
其中 \(a[i]\) 表示 \(P\) 的第 \(i\) 个约数, \(s[i]\) 表示第 \(i\) 个约数的出现次数
分别对应继承上一轮 , 转移 , 只选这一种的情况

对于每一个询问 \(w_{i}\)我们容易得出答案就是 \(\sum{_{a[i]|w_{i}}F[n][i]}\)
事实上我们可以发现,如果一个数既是 \(P\) 的约数,又是 \(w_{i}\)的约数,那么它一定是 \(gcd(P,w_{i})\)约数,
因此我们只需要统计 \(\sum{_{a[i]|gcd(P,w_{i})}F[n][i]}\)
而这可以在DP之后就预处理出来 : \(G[i]=\sum{_{a[j]|a[i]}F[n][j]}\)

[JSOI2018]机器人 , 详见代码

关于这道题的找规律 : 首先对于这种循环或者矩形上的操作可以先考虑正方形 ,
发现对于\(3*3\)的正方形一定是横竖分别走1步和2步才能回到原点 ;但这太小了
对于\(5*5\)的正方形除了\(1\)步和\(4\)步还有\(2\)步和\(3\)步 , 而\(4*4\)的正方形却不能是\(2\)步和\(2\)
猜一个结论 : 必须是互质的 , 否则不兼容; 更细心还可以发现 , 循环的步数还必须是\(n\) ; 不然有些点就会走不到或者提前撞到 , 即不会走满

猜测正方形嵌套到长方形里面会怎么样 , 发现这时每个块里的线的形状都是一样的 .
为什么会这样呢 ? 也许这时正方形的排布也要满足长和宽互质 , 否则不兼容 .
只有互质的 , 才是兼容的 , 才能跑满跑完 .
所以要找到\(d=gcd(n,m)\) , 分成\(d*d\)的正方形去做
而对于循环内的顺序却是不重要的

然后就是\(DP\)了 , \(DP\)也很巧妙
在一组合法的循环方案中 , \(fir[x][y]\)表示\((x,y)\)这个点在第几轮会第一次撞到 ,
然后要统计第\(k\)轮撞到\((x,y)\)的方案数 , 考虑这个就可以只用看这个循环的正方形了
可以发现一条路径如果撞上\((x,y)\) , \((x,y)\)之前的经过点都必须满足\(fir[i][j]>fir[x][y]\) , 在\((x,y)\)之后的经过点都必须满足\(fir[i][j]>=fir[x][y]\)
从左上往右下 , 从右下往左上分别做\(DP\)就好了

[JLOI2015]骗我呢 , 详见代码

神仙题只能看神仙题解

\(dp[i][j]\) 表示第 \(i\) 行没有出现过的数是 \(j\) 的方案数

\(dp[i][j]=∑_{k=0}^{j+1}dp[i−1][k]\)

优化后为\(dp[i][j]=dp[i−1][j+1]+dp[i][j−1]\)

不管怎么样 , 先把好设的状态设出来再说

画图转化为 : 从原点出发,只能向右或向上走,不接触直线\(A,B\),到达点\((n+m+1,n)\)的路径条数

\((x,y)\)的不合法的方案为先穿过\(A\)或先穿过\(B\)

先穿过\(A\)的实现方式是 : \((x,y)\)沿\(A\)翻折 , 减去答案 ; 将翻折过的点沿\(B\)翻着 , 加上答案 ; 再沿A翻折...

同理计算以 \(B\) 开头的方案,就是先沿 \(B\) 折就好了

具体细节的话沿着 \(A\) 折是 \((x,y)->(y-1,x+1)\) ,沿着 \(B\) 折是 \((x,y)->(y+(m+2),x-(m+2))\)

[NOIP2018]填数游戏 , 只会50分\(\dots\)

转载于:https://www.cnblogs.com/lizehon/p/10630597.html

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值