【洛谷5052】[COCI2017-2018#7] Go(区间DP)
作者:互联网
- 有\(n\)个房子和\(m\)个奖励,第\(i\)个奖励形如在第\(ti_i\)个时刻前到达第\(a_i\)个房子(\(a_i\)互不相同)可以获得\(v_i\)的收益。
- 求从第\(k\)个房子出发能获得的最大总收益。
- \(k\le n\le10^3,m\le100,ti_i\le2\times10^3\)
区间\(DP\)
由于我们走过的范围必然是包含起点\(k\)的一个区间,且我们肯定只会选择在某个奖励屋回头,因此可以设\(f_{i,j,t,0/1}\)表示走到过第\(i\sim j\)个奖励屋,当前时刻为\(t\),正处于左/右端点时的最大收益。
注意,如果起点\(k\)不是奖励屋,方便起见可以在起点随便设个奖励。
转移时只需考虑从哪个起点出发向哪个方向扩展一步,共四种情况简单讨论一下即可。
代码:\(O(m^2t)\)
#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define M 100
#define T 2000
#define Gmax(x,y) (x<(y)&&(x=(y)))
using namespace std;
int n,m,k,a[M+5],v[M+5],ti[M+5],f[M+5][M+5][T+5][2];
int main()
{
RI i,j,t,p;for(scanf("%d%d%d",&n,&k,&m),i=1;i<=m;++i) scanf("%d%d%d",a+i,v+i,ti+i);
for(i=m+1;a[i-1]>=k;--i);if(a[i]^k) {for(j=++m;j^i;--j) a[j]=a[j-1],v[j]=v[j-1],ti[j]=ti[j-1];a[i]=k,v[i]=0;}k=i;//强制k为奖励屋
for(i=k;i;--i) for(j=k;j<=m;++j) for(t=0;t<=T;++t) f[i][j][t][0]=f[i][j][t][1]=-1e9;f[k][k][0][0]=v[k];//初始化
RI ans=0;for(i=k;i;--i) for(j=k;j<=m;++j) for(t=0;t<=T;++t) Gmax(ans,f[i][j][t][0]),Gmax(ans,f[i][j][t][1]),//更新答案
i^1&&t+a[i]-a[i-1]<=T&&Gmax(f[i-1][j][t+a[i]-a[i-1]][0],f[i][j][t][0]+(t+a[i]-a[i-1]<ti[i-1]?v[i-1]:0)),//从左端点向左扩一步
i^1&&t+a[j]-a[i-1]<=T&&Gmax(f[i-1][j][t+a[j]-a[i-1]][0],f[i][j][t][1]+(t+a[j]-a[i-1]<ti[i-1]?v[i-1]:0)),//从右端点向左扩一步
j^m&&t+a[j+1]-a[i]<=T&&Gmax(f[i][j+1][t+a[j+1]-a[i]][1],f[i][j][t][0]+(t+a[j+1]-a[i]<ti[j+1]?v[j+1]:0)),//从左端点向右扩一步
j^m&&t+a[j+1]-a[j]<=T&&Gmax(f[i][j+1][t+a[j+1]-a[j]][1],f[i][j][t][1]+(t+a[j+1]-a[j]<ti[j+1]?v[j+1]:0));//从右端点向右扩一步
return printf("%d\n",ans),0;
}
标签:洛谷,COCI2017,奖励,起点,ti,--,Reg,DP,define 来源: https://www.cnblogs.com/chenxiaoran666/p/Luogu5052.html