【NOIP模拟】艾比所特

92 篇文章 0 订阅

Description

阿良良木历将要迎来人生(不,是吸血鬼生涯)的第二次战斗——与身为人类和吸血鬼混血儿的艾比所特在直江津高中的操场solo,以取回Heartunderblade的左脚。
艾比所特个子不大,却单手扛着一副形状比自己大三倍,重量是他体重乘三次方的巨大十字架。吸血鬼是怕十字架的,所以历要远远地躲着。更麻烦的是艾比所特能变成雾气,历攻击不到他,他却因为是混血儿,吸血鬼的弱点降到了mininum,可以碰十字架。直到历用沙子使艾比所特显形,历才获得胜利。
可以把直江津高中的操场看成排成一条直线的n个点,其中第i个点位于数轴上的位置x[i]。如果从i跳到j,首先要花费时间|x[j]-x[i]|。假如i

Solution

这道题,题意很奇怪,字句间暗藏玄机。
我开始还以为是只用找一个环,那么就是值最大的欧拉回路。
然后其实是可以有很多个简单环的。

那么就有一个很显然的性质

每个点的入度和出度只有1。
我们设f[i][j][k]表示做到第i个点,在1~i之间有j个点的还没有出度,有k个点还没有入度。
我们考虑从第i个点推向第i+1个点。
第一种情况:前i个点有一个点连向第i+1个点,第i+1个点又连回来——> f[i+1][j1][k1]=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都是同时加减的,所以三维可以合并为二维。
其实还可以继续缩小,当然是滚动啦。

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#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]);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值