DP从入门到入土
DAGDP
食物链
简单的拓扑DP,转移方程通式 \(f[v]+=f[u],rd[v]--\)
犯错
for (int i=head[u];i;i=e[i].nxt)
{
int v=e[i].v;
f[v]+=f[u];
rd[v]--;
if (!rd[v]) q.push(v);
}
/*6,v写成i*/
for (int i=1;i<=n;i++)
if (!rd[i])
{
if (cd[i]) f[i]=1;
q.push(i);
}
/*特殊情况的处理,入队的对象*/
区间DP
P3205 [HNOI2010]合唱队
这是一种区间DP的典型模板,左右操作,求方案数
对于这类问题,可以分别表示左右两种操作
\(f[i][j]\) 表示在区间 \([i,j],i\) 从左边插入
\(g[i][j]\) 表示在区间 \([i,j],j\) 从右边插入
两个dp数组自然拥有独特的两个阶段
- 对于 \(f\): 相对于上一区间,要么是从 \(i+1\) 比较,再加入,或者上一次加进去的是 \(j\) ,则阶段为\(f[i+1][j],g[i+1][j]\),
注意这是上一阶段,换句话说就是该阶段的 \(i\)是被加入的,也就是上一阶段是不存在 \(g[i][j]\)这中转移状态 - 对于 \(g\): 同理可耻,要么是上一次加入的是 \(i\),也就是加到左边,即 \(f[i][j-1]\),要么就是上一次加进去的是 \(j-1\) ,即 \(g[i][j-1]\);
注意上一阶段,不存在 \(j\) 的情况
错误 转移方程式抄错
for (int len=2;len<=n;len++)
for (int i=1;i+len-1<=n;i++)
{
int j=i+len-1;
f[i][j]=(f[i+1][j]*(a[i+1]>a[i])+g[i+1][j]*(a[i]<a[j]))%mod;
g[i][j]=(f[i][j-1]*(a[j]>a[i])+g[i][j-1]*(a[j]>a[j-1]))%mod;
}
/*6,抄错,炒成:g[i][j]=(g[i][j-1]*(a[j]>a[i])+g[i][j-1]*(a[j]>a[j-1])%mod/
总结 此类区间DP,转移的方向明确,要么上一阶段的左边要么右边,不需要区间枚举
Code
序列DP
粉刷匠
序列DP
对于每一行 \(f[i][j]=max(f[k][j-1]+max(蓝 红,[k,i])\)
对于每一行 \(dp[i][j]\),\(i\)表示行号,
\(dp[i][j]=max(dp[i][j-k]+f[m][k]);\)
答案 \(dp[n][T]\);
注意 处理前缀和优化时出现了错误
for (int k=0;k<l;k++)
{
// int s1=a[i][l]-a[i][k];
// int s2=b[i][l]-b[i][k];
int js=sum[i][l]-sum[i][k];
f[l][r]=max(f[l][r],f[k][r-1]+max(js,l-js-k));
}
树形DP
小齐挖矿
对于一个子节点,距离最近的要么就是父亲,要么就是父亲去的仓库
女仆咖啡厅桌游吧
tmd 燃起来了! 有点饲喂量的树形DP
-
暴力做法 求每个点的 \(LCA\)直接询问,不过会超时
-
树形DP
首先 \(LCA\)的一种性质,如果以 \(i\) 为节点的子树具有相同的最近公公祖先 \(i\),换句话说,若果这个点是某两个点的LCA,那么他的父亲必然是公公祖先
就这一性质,我们假设 \(u\) 即节点是第 \(k\) 层节点的最近公共祖先,那么就看看他的儿子 \(v\)是不是 \(k+1\)的了,
但是要 \(v\)成为深度 \(k+1\) 的LCA,必须满足子树 \(v\) 的最大深度超过 \(k+1\),故我们需要预处理出每个节点的最大深度
还有一种情况,如果 \(u\) 的儿子有多个,假若存在两个以上的 \(v_1,v_2..\) 满足 \(f(v)>=k+1\) (\(f[v]\)表示该点的最大深度),那么他们都不可以成为LCA
P4438 [HNOI/AHOI2018]道路
记忆化搜索,树形思想,公式迷惑
P2899 [USACO08JAN]Cell Phone Network G
水题
P2458 [SDOI2006]保安站岗
水题
换根DP
P3478 [POI2008]STA-Station
换根式子:\(f[v]=-size[v]+f[u]+(n-size[v])\)
用人话讲就是:根有 \(u\) 到 \(v\)时,子树 \(u\) 全体深度+1(不含子树\(v\)),子树 \(v\)全体深度-1
P2986 [USACO10MAR]Great Cow Gathering G
换根水题
\(ans\)记得开大点,否则60
转移式子:\(dp[v]=dp[u]-size[v]\times e[i].w+(sum-size[v])\times e[i].w\)
背包DP
关于二进制神奇做法的背包,感觉是在每一位二进制上进行背包
两个转移点
- 同级转移,我们有
\(f[i][j]=max\{f[i][j-a[i]]+val[i]\}\) - 高位转低位我们有
\(f[i][j]=max\{f[i][j-k]+f[i-1][min(1000,(k<<1)|((w\&(1<<(b-1)))!=0)]\}\)
二进制拆分,注意数组越界(拆分写挂,变成负数)
[P1782](https://www.luogu.com.cn/problem/P1782)
典型的旅行商问题,多重背包里套完全背包,我用的是二进制拆分(真好用,虽然60,这里建议直接吸氧!
期望DP
P1654 OSU!
装压DP
讲真的,装压是我见过最优美的DP题目
\(f[i][s]\) 表示起点为 \(i\),完成状态为 \(s\) 的最小距离
转移有 \(f[i][s]=min\{f[j][s-(1<<(i-1)]+dis(i,j)\}\)
优美之处在于:距离不是限制矩阵的大小,只是运算的工具,通过位运算进行判重 if(!(s&(1<<(i-1))
,转移也非常优美,更新新的起点,并在二进制状态下更新,beautiftying
[USACO12MAR]Cows in a Skyscraper G
这题让初次学习的我知道了初始化,通过判断该点是否在状态之中,可谓妙哉!if((j)&(1<<k))
\(f[i][j]\) 表示有i个层时,满状态下的最小体积书
最后用过倒叙判断是否为inf
即可
P3226 [HNOI2012]集合选数
一道构造好题!