Codeforces Round #307 (Div. 2)C - GukiZ hates Boxes(二分+贪心)

10 篇文章 0 订阅
3 篇文章 0 订阅

题目链接
题目大意:
一段长度为n的路上分布着石头,让m个同学从0开始去搬石头。每个同学每秒钟可以向右移动一步,或者移除当前位置的一块石头,问最少需要多少时间能搬完所有的石头

做法一:
二分时间t,然后让一个人工作t时间(有石头就搬,没有就向右走),如果工作未完成继续派出一个人去工作t时间。

#include<bits/stdc++.h>
#define ll long long
#define IOS {ios::sync_with_stdio(0);cin.tie(0);}
using namespace std;
const int N = 1e5+1000;
int n,m,a[N],k,old[N];
ll min(ll a,ll b){
    if(a <= b) return a;
    else return b;
}
bool ok(ll ans,int a[]){
    ans --;
    int i,pos=1;
    int use = 1,sub = 0;
    ll last=ans;
    while(1){
        if(sub==k) return 1;
        if(last==0) {last = ans-pos+1;use++;}
        if(use>m) return 0;
        ll cost;
        if(a[pos]>0){
            cost = min(a[pos],last);
            a[pos] -= cost;
            last -= cost;
            if(a[pos]==0) sub++;
            continue;
        }
        if(a[pos]==0){
            pos++;
            last--;
        }
    }
}
int main(){
   // freopen("a.txt","r",stdin);
    IOS;
    int i;
    cin>>n>>m;
    for(i = 1;i <= n;i ++){
        cin>>a[i];
        if(a[i]>0) k ++;
    }
    memcpy(old,a,sizeof(old));
    ll l,r;
    l = 1; r = 1e18;
    while(l+1<r){
        ll mid = l+r>>1;
        memcpy(a,old,sizeof(a));
        if(ok(mid,a)) r = mid;
        else l = mid;
    }
    memcpy(a,old,sizeof(a));
    if(ok(l,a)) cout<<l;
    else cout<<r;
    return 0;
}

做法二:
二分时间t,显然最后一秒一定在搬最右边的石头。设最右边的坐标为pos,那么需要在time=t-pos+1的时间内搬完这堆石头。至少需要派出need=ceil(a[i]/(t-pos+1))个人去搬,在路上最多可以耽误need*time-a[i]的时间,这些时间可以用来移除前面遇到的石头。

#include<bits/stdc++.h>
#define ll long long
#define IOS {ios::sync_with_stdio(0);cin.tie(0);}
using namespace std;
const int N = 1e5+1000;
int n,m,a[N],k,old[N];
ll min(ll a,ll b){
    if(a <= b) return a;
    else return b;
}
bool ok(ll ans,int a[]){
    int i;
    ans --;
    ll use=0,last=0;
    for(i = n;i >= 1;i --){
        ll p;
        p = min(a[i],last);
        a[i]-=p;
        last-=p;
        if(a[i]==0) continue;
        if(ans-i+1<=0) return 0;
        ll k = ceil(1.0*a[i]/(ans-i+1));
        use += k;
        last += ((ans-i+1)*k)-a[i];
    }
    if(use>m) return 0;
    return 1;
}
int main(){
    freopen("a.txt","r",stdin);
    IOS;
    int i;
    cin>>n>>m;
    for(i = 1;i <= n;i ++){
        cin>>a[i];
        if(a[i]>0) k ++;
    }
    memcpy(old,a,sizeof(old));
    ll l,r;
    l = 1; r = 1e18;
    while(l+1<r){
        ll mid = l+r>>1;
        memcpy(a,old,sizeof(a));
        if(ok(mid,a)) r = mid;
        else l = mid;
    }
    memcpy(a,old,sizeof(a));
    if(ok(l,a)) cout<<l;
    else cout<<r;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值