NOIP提高组 艾比所特

67 篇文章 1 订阅
55 篇文章 0 订阅

Description

阿良良木历将要迎来人生(不,是吸血鬼生涯)的第二次战斗——与身为人类和吸血鬼混血儿的艾比所特在直江津高中的操场solo,以取回Heartunderblade的左脚。

艾比所特个子不大,却单手扛着一副形状比自己大三倍,重量是他体重乘三次方的巨大十字架。吸血鬼是怕十字架的,所以历要远远地躲着。更麻烦的是艾比所特能变成雾气,历攻击不到他,他却因为是混血儿,吸血鬼的弱点降到了mininum,可以碰十字架。直到历用沙子使艾比所特显形,历才获得胜利。

可以把直江津高中的操场看成排成一条直线的n个点,其中第i个点位于数轴上的位置x[i]。如果从i跳到j,首先要花费时间|x[j]-x[i]|。假如i< j,还需额外花费时间d[i]+a[j],如果i>j,需额外花费时间c[i]+b[j]。

历在战后开始考虑一个新的问题。首先定义艾比所特的攻击:历跳到一个点,然后艾比所特会向这个点扔一个十字架,有十字架的点历无法再次到达。历每次行动可以选择若干个没有十字架的点,然后在其中一个点开始(此时艾比所特不会向这个点扔十字架),按某种顺序跳过所有点,最终跳回开始的点。经过若干次这样的行动后,他最多能拖延多少时间。(一次行动到下一次之间不会消耗时间)

Data Constraint

20%:n,m≤8

40%:n,m≤100

100%:1≤n,m≤5000 1≤ai,bi,ci,di≤ 109 xi的绝对值不超过 109

Solution

我看到这道题就想到了之前CF上一道类似的题,毫无疑问这种题就要上dp。对于一个简单环来说,一个点有且只有一个出边和一个入边。于是我们设出状态F[I][J][K]表示当前做到第i个点,前i个点中有j个点出边连向编号比i大的点,有k个点入边连向编号比i大的点。

于是我们分类讨论点i的出边和入边情况。

1、点i连向的出边和入边都编号都小于i。这时我们发现第i个点对答案的贡献实为a[i]+c[i]+x[i]*2,而由此可以由f[i-1][j][k]转移到f[i][j-1][k-1]。

2、点i连向的出边和入边都编号都大于i。这时我们发现第i个点对答案的贡献实为b[i]+d[i]-x[i]*2,而由此可以由f[i-1][j][k]转移到f[i][j+1][k+1]。

3、点i连向的出边编号大于i和入边编号小于i。这时我们发现第i个点对答案的贡献实为d[i]+a[i],而由此可以由f[i-1][j][k]转移到f[i][j][k]。

4、点i连向的出边编号小于i和入边编号大于i。这时我们发现第i个点对答案的贡献实为c[i]+b[i],而由此可以由f[i-1][j][k]转移到f[i][j][k]。

我这样理解:对于f[i-1][j][k],当你i选择一个编号比自己小的入边或出边时,实际上也从j个连向编号比i-1大的点的出边或k个连向编号比i-1大的点的入边中减少了一条连向编号比i大的点的入边或出边。

我们可以发现,每次状态转移时j和k都是同时加减的,所以我们可以减少一维,只要设出f[i][j]即可。时间复杂度为O( N2 )。

代码

#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define ll long long
using namespace std;
const int maxn=5005;
int n,i,t,j,k,l;
ll a[maxn],b[maxn],c[maxn],d[maxn],f[maxn][maxn],x[maxn],p;
int main(){
//  freopen("data.in","r",stdin);
    scanf("%d",&n);
    for (i=1;i<=n;i++)
        scanf("%lld",&x[i]);
    for (i=1;i<=n;i++)
        scanf("%lld",&a[i]);
    for (i=1;i<=n;i++)
        scanf("%lld",&b[i]);
    for (i=1;i<=n;i++)
        scanf("%lld",&c[i]);
    for (i=1;i<=n;i++)
        scanf("%lld",&d[i]);
    memset(f,128,sizeof(f));f[0][0]=0;p=f[1][1];
    for (i=0;i<n;i++)
        for (j=0;j<=i;j++){
            if (f[i][j]==p) continue;
            if (i){
                if (j) {f[i+1][j-1]=max(f[i][j]+x[i+1]*2+a[i+1]+c[i+1],f[i+1][j-1]);
                if (i!=n-1){
                    f[i+1][j]=max(f[i][j]+a[i+1]+d[i+1],f[i+1][j]);
                    f[i+1][j]=max(f[i][j]+b[i+1]+c[i+1],f[i+1][j]);
                }
                }
            }
            if (i!=n-1) f[i+1][j+1]=max(f[i][j]+b[i+1]+d[i+1]-x[i+1]*2,f[i+1][j+1]);
        }
    printf("%lld",f[n][0]);
}
  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值