ZOJ 3627 Treasure Hunt II


题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3627


题目大意:有n个城市,每个城市有个宝藏值,有两个人现在在s城市,每天每个人都可以走到相邻城市,但是他们之间的距离不能超过m,问t天内他们最多能拿到多少宝藏?

   数据在

贪心+模拟


首先,距离没达到m的时候,两人肯定是往相反方向走为最优。

当距离达到m之后,只有2种可能,向左走一段再返回再向右走一段,向右走一段再返回再向左走一段【也就是左边走2次或者右边走2次】

然后我们枚举向右走了多少个城市,可以用O(1)算出来向左最多可以走多少个城市。

然后枚举是左边走了2次还是右边走了2次,记下最大值即可。


另外有个问题 如果m为奇数,两人往相反方向走的时候,会出现多出1步的情况,这时候就要枚举多的这一步是给左边还是给右边,再进行计算。

总的来说算法不难,但是细节处理上比较恶心。


代码:

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<string>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<map>
#include<vector>
#include<queue>

using namespace std;

#define sf scanf
#define pf printf
#define pfn printf("\n");
#define ll long long
#define INF 0x7fffffff
#define EPS (1e-10)
#define FEQ(a,b) (fabs((a) - (b)) < EPS)

ll n,P,M,T,ans,p,q;
ll a[100001],suml[100001],sumr[100001];
ll anst;
ll ttt;
void find()
{
    ll t,temp;
    ll ans2=0;
     if(p-1<=T)
        ans2 = suml[p-1];
    else
        ans2 = suml[p-1] - suml[p-1-T];
    for(int i = q+1; i<=n; i++){
        if(i-q>T)
            break;
        t = (T - (i-q))/2;
        if(p-t<=0)
            temp = suml[p-1];
        else
            temp = suml[p-1] - suml[p-t-1];
        temp += sumr[q+1] - sumr[i+1];
        if(temp>ans2)
            ans2 = temp;
        t = (T - (i-q)*2);
        if(t>=0){
            if(p-t<=0)
                temp = suml[p-1];
            else
                temp = suml[p-1] - suml[p-t-1];
            temp += sumr[q+1] - sumr[i+1];
            if(temp>ans2)
                ans2 = temp;
        }
    }
    anst=max(anst,ans2+ttt);
}
void D(){
    anst=0;
    bool flagl,flagr;
    p = q = P;
    flagl = flagr = true;
    ttt=0;
    while(T){
        if(q-p+2>M)
            break;
        if(flagl)
            p--;
        if(flagr)
            q++;
        if(p==0){
            p++;
            flagl=false;
        }
        if(q==n+1){
            q--;
            flagr=false;
        }
        if(flagl)
            ans += a[p];
        if(flagr)
            ans += a[q];
        T--;
    }
    if(T==0)
      return;
    if(p==0)
        p++;
    if(q==n+1)
        q--;
    if(p==1&&q==n)
    {}
    else if(q-p==M)
       find();
    else
    {
        if(p==1)
        {
           q++;
           T--;
           ans+=a[q];
           find();
        }
        else if(q==n)
        {
            p--;
            T--;
            ans+=a[p];
            find();
        }
        else
        {
           q++;
           T--;
           ttt=a[q];
           find();
        //   ans-=a[q];
           q--;
           p--;
           ttt=a[p];
           find();
        }
    }  
    ans+=anst;
}

int main()
{
    while(scanf("%lld %lld",&n,&P)!=EOF){
        memset(a,0,sizeof(a));
        for(int i=1; i<=n; i++){
            scanf("%lld",&a[i]);
        }
        memset(sumr,0,sizeof(sumr));
        memset(suml,0,sizeof(suml));
        suml[0] = 0;
        suml[1] = a[1];
        for(int i=2; i<=n; i++)
            suml[i] =suml[i-1] + a[i];
        sumr[n] = a[n];
        for(int i=n-1; i>=1; i--)
            sumr[i] = sumr[i+1] + a[i];
        scanf("%lld %lld",&M,&T);
        ans = a[P];
        D();
        printf("%lld\n",ans);
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值