阿良良木历将要迎来人生(不,是吸血鬼生涯)的第二次战斗——与身为人类和吸血鬼混血儿的艾比所特在直江津高中的操场solo,以取回Heartunderblade的左脚。
艾比所特个子不大,却单手扛着一副形状比自己大三倍,重量是他体重乘三次方的巨大十字架。吸血鬼是怕十字架的,所以历要远远地躲着。更麻烦的是艾比所特能变成雾气,历攻击不到他,他却因为是混血儿,吸血鬼的弱点降到了mininum,可以碰十字架。直到历用沙子使艾比所特显形,历才获得胜利。
可以把直江津高中的操场看成排成一条直线的n个点,其中第i个点位于数轴上的位置x[i]。如果从i跳到j,首先要花费时间|x[j]-x[i]|。假如i
这道题,题意很奇怪,字句间暗藏玄机。
我开始还以为是只用找一个环,那么就是值最大的欧拉回路。
然后其实是可以有很多个简单环的。
每个点的入度和出度只有1。
我们设f[i][j][k]表示做到第i个点,在1~i之间有j个点的还没有出度,有k个点还没有入度。
我们考虑从第i个点推向第i+1个点。
第一种情况:前i个点有一个点连向第i+1个点,第i+1个点又连回来——> f[i+1][j−1][k−1]=max(f[i+1][j+1][k+1],f[i][j][k]+x[i+1]∗2+a[i+1]+c[i+1]);
第二种情况:前i个点有一个点连向第i+1个点,第i+1个点往后面连——> f[i+1][j][k]=max(f[i+1][j][k],f[i][j][k]+a[i+1]+d[i+1]); 为什么j和k没有-1呢?因为推到i+1是又会多一个点的,那么影响j和k的点原本是又会多一个,但是这里会抵消一个,上面的那种情况会抵消两个。
第三种情况:第i+1个点连向前i个点的一个点,i+1后面的点连向第i+1个点——> f[i+1][j][k]=max(f[i+1][j][k],f[i][j][k]+b[i+1]+c[i+1]);
第四种情况:i+1后面的点连向第i+1个点,第i+1个点又连向i+1后面的点——> f[i+1][j+1][k+1]=max(f[i+1][j+1][k+1],f[i][j][k]−x[i+1]∗2+b[i+1]+d[i+1]); 这种情况不会抵消。
注意边界条件,前三种情况是在j>0||k>0的时候才能向后推的,因为都与i前面的点有关,前面的点用完了,自然不能连。
我们发现j和k都是同时加减的,所以三维可以合并为二维。
其实还可以继续缩小,当然是滚动啦。
#include
#include
#include
#include
#include
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fod(i,a,b) for(i=a;i>=b;i--)
#define rep(i,a) for(i=first[a];i;i=next[i])
using namespace std;
typedef long long ll;
const int maxn=10007;
ll i,j,k,l,t,n,m,ans,da;
ll x[maxn],a[maxn],b[maxn],c[maxn],d[maxn],p,q;
ll f[2][maxn];
int main(){
scanf("%lld",&n);
fo(i,1,n)scanf("%lld",&x[i]);
fo(i,1,n)scanf("%lld",&a[i]);
fo(i,1,n)scanf("%lld",&b[i]);
fo(i,1,n)scanf("%lld",&c[i]);
fo(i,1,n)scanf("%lld",&d[i]);
memset(f,128,sizeof(f));da=f[0][0];
f[0][0]=0;p=0;
fo(i,0,n-1){
q=p^1;
fo(j,0,i){
if(f[p][j]==da)continue;
if(j){
f[q][j-1]=max(f[q][j-1],f[p][j]+x[i+1]*2+a[i+1]+c[i+1]);
f[q][j]=max(f[q][j],f[p][j]+a[i+1]+d[i+1]);
f[q][j]=max(f[q][j],f[p][j]+b[i+1]+c[i+1]);
}
f[q][j+1]=max(f[q][j+1],f[p][j]-x[i+1]*2+b[i+1]+d[i+1]);
}
p=p^1;
}
printf("%lld\n",f[p][0]);
}