2025.2.19 做题记录
今日补题内容:一道区间dp+一道树形dp
对不起我再也不摆了qwq
Greedy Pie Eaters P
观察到不可做,于是放弃。观察到是区间 dp 定义 \(f_{l,r}\) 为 \(l,r\) 区间内的最大收益,枚举断点 \(k\) 最大化 \(f_{l,k}+f_{k+1,r}\) 。但我们还需要考虑每个人都要吃,所以需要预处理出一个 \(val_{l,r,k}\) 数组表示为 \(l,r\) 区间内吃 \(k\) 获得的最大收益。预处理 \(val\) 数组的操作相当于也是区间dp。详见代码:
#include<iostream>
#include<queue>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
const int N=3e2+5;
int n,m;
int val[N][N][N];
long long f[N][N];
int v,x,y;
int main(){
cin>>n>>m;
for(int i=1;i<=m;i++){
cin>>v>>x>>y;
for(int j=x;j<=y;j++){
val[x][y][j]=v;
}
}
for(int len=1;len<=n;len++){
for(int i=1;i+len-1<=n;i++){
int j=i+len-1;
for(int k=i;k<=j;k++){
val[i][j][k]=max(val[i][j][k],max(val[i+1][j][k],val[i][j-1][k]));
}
}
}
for(int len=1;len<=n;len++){
for(int i=1;i+len-1<=n;i++){
int j=i+len-1;
for(int k=i;k<j;k++){
f[i][j]=max(f[i][j],f[i][k]+f[k+1][j]);
}
for(int k=i;k<=j;k++){
f[i][j]=max(f[i][j],f[i][k-1]+f[k+1][j]+val[i][j][k]);
}
}
}
cout<<f[1][n];
return 0;
}
叶子的染色
遍历每一个节点,我们强制认为它必须染色。定义 \(f_{u,0/1}\) 为节点 \(u\) 选择 \(0/1\) 两种颜色时的情况。
对于颜色不同的情况,因为两个颜色互不影响(只看儿子颜色),所以直接继承 \(f_{v,1/0}\) 。
对于颜色相同的情况,我们肯定会选择父亲(因为可影响的范围更大),所以选择 \(f_{v,0/1}-1\)。
所以方程为:\(f_{u,0/1}+=\min(f_{v,0/1}-1,f_{v,1/0})\)。转移方程对称。
#include<iostream>
#include<queue>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
const int N=1e4+50;
vector<int> vec[N];
int n,m;
int co[N];
int f[N][5];
void dfs(int u,int fa){
for(int i=0;i<vec[u].size();i++){
int v=vec[u][i];
if(v==fa) continue;
dfs(v,u);
f[u][1]+=min(f[v][0],f[v][1]-1);
f[u][0]+=min(f[v][1],f[v][0]-1);
}
}
int main(){
cin>>n>>m;
for(int i=1;i<=m;i++){
cin>>co[i];
}
for(int i=1;i<n;i++){
int u,v;
cin>>u>>v;
vec[u].push_back(v);
vec[v].push_back(u);
}
for(int i=1;i<=n;i++){
f[i][1]=f[i][0]=1;
if(i<=m) f[i][!co[i]]=(int)1e8;
}
dfs(n,0);
cout<<min(f[n][0],f[n][1]);
return 0;
}

浙公网安备 33010602011771号