Loading

做题记录(二)

做题记录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

题目做法
  1. 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\)数组的更新必须有上述方程中的两部分才是正确的,因为事实上先回在走与先走再回都可以更新答案,从而避免因为枚举顺序引发的错误

  2. 贪心

题目反思

要避免因枚举顺序引发的错误

无归岛

2024.1.7

题目做法
  1. 利用性质:分类讨论

  2. DFS树:记录环顶

  3. 园方树,用环形DP解决方点

题目反思

在园方树上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]\)

所以我们需要快速处理区间加与区间最小值,很明显可以用线段树。

题目反思
  1. 单调变化转移费用、单调变化决策集合都可以用单调队列优化DP

  2. 注意状态转移方程的变化带来的优化

  3. 注意初始条件处理的合法性。本题"选 \(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\) 的候选集合一边不变,一边变大,便可以用一个变量维护最大值。

题目反思
  1. 存曲线信息减少状态。对于此题,我们想要限制距离,却存的是上一个点,通过计算得到距离,这样减少了状态。

  2. 状态限制——存上一个。对于此题待更新状态的第二维与决策集合相同,减少决策。

瑰丽华尔兹

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;
} 
题目反思

求同存异,找到相似的处理方式中的共同特点,通过建立顺序,写出函数,减少码量。

posted @ 2025-04-02 15:40  lupengheyyds  阅读(9)  评论(0)    收藏  举报