E. Life Transfer(双指针)

题目链接:https://codeforces.com/gym/102392/problem/E
题意:给定n个人年龄,年龄达到lc才能骑车,骑车可以载k-1人,骑车代价为pc;年龄达到lm才能骑motor,motor不能载人;可以用魔法,将一个人年龄转移到另一个人,转移一岁的代价为t,但不能转移超过d岁,及a岁的人,其年龄变化范围为 [ a − d + 1 , a + d − 1 ] [a-d+1,a+d-1] [ad+1,a+d1].
题解:枚举骑摩托数,将年龄排序,双指针来弄。代码实现具体细节比较多。
代码copy自vj

//coded by ZJUT_7
#include<bits/stdc++.h>
using namespace std;
const int maxn=100010;
#define inf 0x3f3f3f3f3f3f3f3f
#define ll long long
ll a[maxn];


int main(){
    ll n,k,lc,lm,pc,pm,t,d;
    scanf("%I64d%I64d%I64d%I64d%I64d%I64d",&n,&k,&lc,&pc,&lm,&pm);
    scanf("%I64d%I64d",&t,&d);
    for(int i=1;i<=n;i++) scanf("%I64d",&a[i]);
    sort(a+1,a+n+1);
    ll need=0,have=0,cost=0;
    ll ans=inf;
    int illegal=0;
    for(int i=1;i<=n;i++){
        have+=max(0LL,min(d,a[i]-lm));
        need+=max(0LL,min(d,lm-a[i]));
        if(a[i]+d<lm) illegal++;
    }
    cost=pm*n+need*t;
    if(illegal==0&&have>=need) ans=cost;
    int s=1,e=n;
    ll cnt=0;
    while(e-s+1>=k){
        cnt++;
        for(int i=0;i<k-1;i++){
            need-=max(0LL,min(d,lm-a[i+s]));
            have+=min(d,min(lm,a[i+s])-1);
            if(a[i+s]+d<lm) illegal--;
        }
        need+=max(0LL,lc-max(lm,a[e]));
        have-=max(0LL,min(d,a[e]-lm));
        have+=max(0LL,min(d,a[e]-lc));

        if(a[e]+d<lc) break;
        cost=pm*(n-cnt*k)+cnt*pc+need*t;
        if(illegal==0&&have>=need) ans=min(ans,cost);
        s+=k-1;
        e--;
    }
    if(a[e]+d>=lc){
        cnt++;
        for(int i=0;i<e-s;i++){
            need-=max(0LL,min(d,lm-a[i+s]));
            have+=min(d,min(lm,a[i+s])-1);
            if(a[i+s]+d<lm) illegal--;
        }
        need+=max(0LL,lc-max(lm,a[e]));
        have-=max(0LL,min(d,a[e]-lm));
        have+=max(0LL,min(d,a[e]-lc));
        cost=cnt*pc+need*t;
        if(illegal==0&&have>=need) ans=min(ans,cost);
    }
    if(ans!=inf)
        printf("%I64d\n",ans);
    else
        puts("-1");
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值