P5851 [USACO19DEC] Greedy Pie Eaters P

n,m较小,同时又是区间问题,可以考虑区间dp。
设定\(f[i][j]\)为只在i ~ j 范围内操作的最大贡献,为了将操作表示出来可以设g[k][i][j]为在i ~ j 内操作一次的包括k点最大贡献。
通过这些可以推出:
\(f[i][j]=max_{k=i}^jf[i][k-1]+f[k+1][j]+g[k][i][j]\),这样一来两边的操作也不会冲突,又可以保证一定可以一次操作因为中间一定留了一个k点。
反过来看g,也就是又一次区间dp的操作罢了,对于一头牛的\(l_i,r_i\),把\(x\in[l_i,r_i]\)\(g[x][l_i][r_i]=w_i\)就是初始化,然后只需要最大贡献,于是取最大值,\(g[k][i][j]=max(g[k][i+1][j],g[k][i][j-1])\)

#include<algorithm>
#include<stdio.h>
#define ll long long
using namespace std;
int n,m;
ll g[305][305][305];
ll f[305][305];
int main() {
//	freopen("P5851.in","r",stdin);
//	freopen("P5851.out","w",stdout);
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++) {
		ll w;int l,r; scanf("%lld%d%d",&w,&l,&r);
		for(int k=l;k<=r;k++) g[k][l][r]=max(g[k][l][r],w);
	}
	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][r],max(g[k][l+1][r],g[k][l][r-1]));
			}
		}
	}
	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++) {
				f[l][r]=max(f[l][r],f[l][k-1]+g[k][l][r]+f[k+1][r]);
			}
		}
	}
	printf("%lld",f[1][n]);
	return 0;
}
posted @ 2024-02-17 20:54  Ian8877  阅读(7)  评论(0)    收藏  举报