P5851 [USACO19DEC]Greedy Pie Eaters P

如果只考虑选哪些奶牛吃派和奶牛吃派的顺序,就会陷入僵局,那么我们可以考虑派的情况。

套路地令 \(f_{i,j}\) 表示 \(i\sim j\) 这一段派,能满足的奶牛的最大可能体重。那么问题又来了,暴力枚举一头奶牛转移过来是 \(n^2m\) 的,怎么办呢?

发现奶牛最少吃一个派这个条件可以利用,可以在状态中记录这个派的位置。

所以我们再搞一个 \(g\) 数组,令 \(g_{i,j,k}\) 表示满足 \(i\leq l\leq k\leq r\leq j\) 的体重最大的奶牛。

显然这只奶牛吃派不会影响到 \(i\sim j\) 范围之外的派,且如果 \(k\) 位置的派还存在这只奶牛必定能吃。

借助 \(g\) 数组后转移方程很容易就能写出来:\(f_{i,j}=\max\{f_{i,k-1}+f_{k+1,j}+g_{i,j,k}\}\)

\(g\) 数组的计算也很简单,实际上就是预处理一个区间 \(\max\)\(g_{i,j,k}=\max\{g_{i+1,j,k},g_{i,j-1,k}\}\),但是需要注意初始化,即每只奶牛可以拿 \(l\sim r\) 中的任意一个派保底,\(g_{l,r,l\sim r}=w\)(数据保证奶牛吃派的区间两两不同,所以不用取 \(\max\))。

分析一下我们的优化,其实就是通过预处理将枚举奶牛变成了枚举保底的派,使 \(m\) 降到了 \(n\)

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

code:

#include<bits/stdc++.h>
using namespace std;
#define N 305
#define Max(x,y)((x)>(y)?x:y)
#define For(i,x,y)for(i=x;i<=(y);i++)
int g[N][N][N],f[N][N];
int main()
{
	int n,m,i,j,w,l,r,len,k;
	scanf("%d%d",&n,&m);
	For(i,1,m)
	{
		scanf("%d%d%d",&w,&l,&r);
		For(j,l,r)g[l][r][j]=w;
	}
	For(len,1,n-1)
	For(i,1,n)
	{
		j=i+len-1;
		if(j>n)break;
		For(k,i,j)g[i][j+1][k]=Max(g[i][j+1][k],g[i][j][k]),g[i-1][j][k]=Max(g[i-1][j][k],g[i][j][k]);
	}
	For(len,1,n)
	For(i,1,n)
	{
		j=i+len-1;
		if(j>n)break;
		For(k,i,j)f[i][j]=Max(f[i][j],f[i][k-1]+f[k+1][j]+g[i][j][k]);
	}
	printf("%d",f[1][n]);
	return 0;
}

猜你喜欢

转载自www.cnblogs.com/May-2nd/p/13380329.html