做题记录(二)
做题记录DP
| 题目名称 | 做题时间 | 题目标签 |
|---|---|---|
| 数字计数 | 2023.12.26 | 计数DP |
| 同类分布 | 2023.12.27 | 计数DP、计算转判断 |
| No Change G | 2024.1.1 | 状压DP、计算转判断(状态存值互换) |
| String painter | 2024.1.1 | 状压DP、线性DP、双DP辅助 |
| You Are the One | 2024.1.1 | 状压DP、顺序性问题 |
| Mondriaan's Dream | 2024.1.3 | 状压DP、状态影响 |
| 愤怒的小鸟 | 2024.1.3 | 状压DP、限定决策顺序优化 |
| 小Q的棋盘 | 2024.1.4 | 树形DP、DP顺序处理、贪心 |
| 排兵布阵 | 2024.1.4 | 状压DP、预处理可行状态 |
| 无归岛 | 2024.1.7 | 园方树、树形DP、拆图计算+合并更新 |
| 世界树 | 2024.1.11 | 虚树DP、分割点 |
| 基站选址 | 2024.1.11 | 线段树优化DP,分次处理 |
| Pogo-Cow S | 2024.1.14 | 间接信息优化状态(用两个点保存距离)、第二维阶段、状态计算限制 |
| 瑰丽华尔兹 | 2024.1.18 | 单调队列优化DP |
小Q的棋盘
2024.1.4
题目做法
-
DP:
建立数组\(dp1[x][step]\)表示从\(x\)开始向子树中走\(step\)步并返回\(x\)的最多经过点,\(dp2[x][step]\)表示从x开始向子树中走step步不一定返回x的最多经过点则
对于x的每个子节点y,\(dp1[x][step]=max(dp1[x][i]+dp1[y][step-i-2]),(i\in[0,step-2])\\dp2[x][step]=max(dp1[x][i]+dp2[y][step-i-1],dp2[x][i]+dp1[step-i-2]),(i\in[0,step-1])\)注意这里对于\(dp2\)数组的更新必须有上述方程中的两部分才是正确的,因为事实上先回在走与先走再回都可以更新答案,从而避免因为枚举顺序引发的错误
-
贪心
题目反思
要避免因枚举顺序引发的错误
无归岛
2024.1.7
题目做法
题目反思
在园方树上DP解决方点的时候,可以用环形DP辅助
基站选址
2024.1.14
题目做法
\(dp[i][k]\)表示只考虑前 \(i\) 个村庄(注意“只考虑”,也就是罚款、修建费都只考虑),修 \(k\) 个基站,且最后一个基站建在i,时的最小费用,则:
\(dp[i][k]=\min\limits_{k-1\le j\le i-1}\{dp[j][k-1]+fine[j][i]\}\)
\(fine[j][i]\)指\(j\sim i\)中需要赔款的村庄
我们发现 \(k\) 是可以循环优化的,所以:
\(dp[i]=\min\limits_{k-1\le j\le i-1}\{dp[j]+fine[j][i]\}\)
注意到,当 \(j\) 固定 \(i\) 小到大的时候,\(fine[j][i]\)的范围单调递增
于是对于每个 \(i\) 我们可以记录最左\(st\)与最右端\(nd\)可以管理 \(i\) 的村庄。
当循环到\(nd\)以后,将\(j:1\sim st-1\)的转移代价\(cost[j]\)加上\(w[i]\),相当于左右都无法管理。很明显,若\(i,j\)之间无需赔偿,则\(cost[j]=dp[j]\)
这时 \(dp[i]=\min\limits_{k-1\le j\le i-1}cost[j]\)
所以我们需要快速处理区间加与区间最小值,很明显可以用线段树。
题目反思
-
单调变化转移费用、单调变化决策集合都可以用单调队列优化DP
-
注意状态转移方程的变化带来的优化
-
注意初始条件处理的合法性。本题"选 \(0\) 个基站"在状态定义上时非法的(因为“最后一个基站建在 \(i\) ”说明必须有一个基站),只能将”选 \(1\) 个基站“当作初始状态。同样的还有yyf不喜欢抽卡牌
Pogo-Cow S
2024.1.14
题目做法
首先对 \(x\) 排序
跟明显可以分为非严格单调递减与非严格单调递增,做法相同。
\(dp[i][j]\) 表示当前 Betty 已经跳到了第 \(i\) 个点,且上一个点是第 \(j\) 个点的最大总得分。
则对于非严格单调递增:\(dp[i][j]=\max\limits_{x[k]-x[j]\le x[i]-x[j],k\le j\le i}\{dp[j][k]\}+p[i]\)
观察到,当 \(j\) 一定时,\(x[i]\) 越大,\(k\) 的候选集合一边不变,一边变大,便可以用一个变量维护最大值。
题目反思
-
存曲线信息减少状态。对于此题,我们想要限制距离,却存的是上一个点,通过计算得到距离,这样减少了状态。
-
状态限制——存上一个。对于此题待更新状态的第二维与决策集合相同,减少决策。
瑰丽华尔兹
2024.1.18
题目做法
首先考虑对于时间t来dp:
\(f[t][i][j]\)表示在第t时刻在第i行第j列所能获得的最长
距离。
转移方程:\(f[t][i][j]=max(f[t-1][i][j],f[t][i*][j*]+1)(i*,j*为上一个合理的位置)\) 这样时间复杂度为\(O(TNM)\),可以过\(50\%\),但对于\(100\%\)TLE且MLE。
所以必须优化,首先把时间\(t\)换成区间\(k\),令\(f[k][i][j]\)表示在第\(k\)段滑行区间中在位置\(i\),
\(j\)所能获得最长距离注意到在第\(k\)段时间内只能向某个方向最多走\(x\)步(\(x\)为区间长度)
得到转移方程\(f[k][i][j]=max(f[k-1][i][j],f[k][i*][j*]+dis(i,j,i*,j*))(i*,j*为上一个合理的位置)\)这个做法的时间复杂度是O(kn^3),会超时,需要进一步优化用单调队列优化掉内层的一个n,就可以做到\(O(kn^2)\),可以AC
本代码中还使用了滚动数组优化 用单调递减队列求最大值时,遇到障碍清空整个队列即可,另外队列比较时需要
加上偏移量dis
#include<bits/stdc++.h>
using namespace std;
const int szl=205;
int n,m,x,y,k;
bool able[szl][szl];
int dp[szl][szl];
int dx[4]={-1,1,0,0},dy[4]={0,0,-1,1};
struct DequeNode{
int val,pos;//由于重新排号,所以都需要记录
};
deque<DequeNode> q;
int ans=0;
void Work(int x,int y,int len,int dct){//共同特点长度len相同
q.clear();
for(int i=1;1<=x&&x<=n&&1<=y&&y<=m;i++,x+=dx[dct],y+=dy[dct])//用xy的变化限制实际的更新,用i将更新范围重新排号,便于统一使用单调队列
if(!able[x][y])q.clear();
else{
while(!q.empty()&&q.front().pos+len<i)q.pop_front();
while(!q.empty()&&q.back().val+i-q.back().pos<dp[x][y])q.pop_back();//每次移动,相当于给队列中所有数加1,单调性不变
q.push_back({dp[x][y],i});
dp[x][y]=q.front().val+(i-q.front().pos);
ans=max(ans,dp[x][y]);
}
}
int main(){
cin>>n>>m>>x>>y>>k;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
char ch;cin>>ch;
able[i][j]=ch=='.';
}
memset(dp,0xcf,sizeof dp);
dp[x][y]=0;
for(int i=1;i<=k;i++){
int s,t,dct;cin>>s>>t>>dct;dct--;
int len=t-s+1;
switch(dct){
case 0:{for(int j=1;j<=m;j++)Work(n,j,len,dct);break;}//规定枚举方向
case 1:{for(int j=1;j<=m;j++)Work(1,j,len,dct);break;}
case 2:{for(int j=1;j<=n;j++)Work(j,m,len,dct);break;}
case 3:{for(int j=1;j<=n;j++)Work(j,1,len,dct);break;}
}
}
cout<<ans;
return 0;
}
题目反思
求同存异,找到相似的处理方式中的共同特点,通过建立顺序,写出函数,减少码量。

浙公网安备 33010602011771号