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;
}
标签:USACO19DEC,P5851,int,ll,305,long,Eaters,操作
From: https://www.cnblogs.com/1n87/p/18018393