*题解:P5851 [USACO19DEC] Greedy Pie Eaters P

题目链接

解析

给定若干带权区间,要求选取一些区间使得每个区间都有独自覆盖的区域的同时权值和最大。

看到数据范围应当考虑区间 dp。

\(f_{l,r}\) 表示考虑完 \([l,r]\) 区域内区间的最大权值。观察区域内区间的性质,尝试找到子问题。根据题目的限制,对于一种最优策略,我们去掉任意一个区间都会有一块或多块区域裸露出来,以这样的区域为中心,便可划分出左右两个子问题。故可以枚举断点 \(k\),找出能覆盖 \(k\) 的一个在 \([l,r]\) 内的权值最大的点,记其为 \(g_{k,l,r}\)。然后有:

\[g_{k,l,r} = \max(g_{k,l,r - 1},g_{k,l + 1,r},w_{l,r})\\ f_{l,r} = \max_{k=l}^{r}(f_{l,k - 1} + f_{k + 1,r} + g_{k,l,r}) \]

其中 \(w_{l,r}\) 表示区间 \([l,r]\) 的权值,不存在则为 \(0\)

时间复杂度 \(O(n ^ 3)\)

代码

/*
*/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N = 300 + 5,M = 4000005,P = 2000000,mod = 998244353;
int w[N][N],g[N][N][N],f[N][N];
signed main(){
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
//	freopen("in.txt","r",stdin);
//	freopen("out.txt","w",stdout);
	int n,m;
	cin>>n>>m;
	for(int i=1;i<=m;i++){
		int x,l,r;
		cin>>x>>l>>r;
		w[l][r] = max(w[l][r],x);
	}
	for(int len=1;len<=n;len++){
		for(int l=1;l + len - 1<=n;l++){
			int r = l + len - 1;
			
			for(int k=l;k<=r;k++){
				g[k][l][r] = max({g[k][l + 1][r],g[k][l][r - 1],w[l][r]});
			}
			
		}
	}
	for(int len=1;len<=n;len++){
		for(int l=1;l + len - 1<=n;l++){
			int r = l + len - 1;
			for(int k=l;k<=r;k++){
				int x = g[k][l][r];
				if(k > l){
					x += f[l][k - 1];
				}
				if(k < r){
					x += f[k + 1][r];
				}
				f[l][r] = max(f[l][r],x);
			}
		}
	}
	cout<<f[1][n];
	return 0;
}
posted @ 2026-05-30 17:45  yutar  阅读(10)  评论(0)    收藏  举报