JZOJ5677. 【GDOI2018Day2模拟4.21】纽约

本文介绍了一个关于纽约转场的问题,模拟蒙古包转场过程,分析如何选择最优载重车辆来减少转场次数。通过非典型的二分查找方法,结合前后验证策略找到最小载重值。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Description

印度洋暖流温润着纽约,四季丰沛的雨水造就了一望无际的大草原。蒙古包是纽约最独特的一道风景线,每至二月中旬,纽约的土著傣族人民又开始半年一度的转场了。
由于牲畜和行李过多,牧民 Azone 不得不多次往返于两个草场之间运输家当。为了顺利转场,Azone 决定花费 w 元津巴布韦币,购买一辆载重为 w 的汽车。共有 n 件家具需要搬运,每件家具的重量为 wi 。Azone 每次出发前,会搬若干件总重不超过 w 的物品上车:出发前,车是空载的,Azone 会选择能搬上车的家具中最重的一件放上车(即该家具之前还未运走且放置该家具后汽车不会超载),然后在剩下的家具中继续选择一件能被搬走的最重的上车,持续装车,直至剩下的家具都塞不上车。装载完毕后,Azone 会开车运走这些家具,卸在目的地,再驾空车返回继续运送,直至转场完毕。
Azone 希望在运送次数不超过 R 的情况下完成转场,求 Azone 最少需要购置价值多少的车。

Input

第一行,两个整数 n 和 R,分别表示家具件数及最多运送次数。
第二行,若干个整数 wi ,表示家具重量。

Output

一行,表示答案。

Sample Input

6 2
26 7 10 30 5 4

Sample Output

42

Data Constraint

subtask 1 60pts,R,n,w i ≤ 20。
subtask 2 40pts,没有额外限制。
对于100% 的数据,1 ≤ R,n,wi ≤ 2000。

题解

像这种题,一看就知道是二分,
然而并不是想象中这么简单。
当打完二分以后,一对拍,
就会发现,其实它并不满足二分性。
虽然说二分出来的这个答案一定是满足题意的,
但它不一定是最小的。
通过比较正确答案与二分出来的答案,
就会发现这两个答案之间相差不会太大,
于是二分出来答案以后,再往前那么几百,
判断一下前面是否有更优的答案。

code

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#define G getchar
using namespace std;
char ch;
void read(int& n)
{
    for(n=0,ch=G();ch<'0' || ch>'9';ch=G());
    for(;'0'<=ch && ch<='9';ch=G())n=(n<<3)+(n<<1)+ch-48;
}
int n,R,a[2003],l,r,mid,ans,pre[2003],nxt[2003];

bool pd(int w)
{
    for(int i=1;i<=n;i++)
        pre[i]=i-1,nxt[i]=i+1;pre[n+1]=n;
    for(int m=1,s=0,x=n;s<n;x=pre[n+1],m++)
    {
        if(m>R)return 0;
        for(int p=w;p>0 && x;x=pre[x])
            if(p>=a[x])
            {
                s++;p-=a[x];
                nxt[pre[x]]=nxt[x];
                pre[nxt[x]]=pre[x];
            }
    }
    return 1;
}

int main()
{
    freopen("newyork.in","r",stdin);
    freopen("newyork.out","w",stdout);
    read(n);read(R);
    for(int i=1;i<=n;i++)
        read(a[i]),r+=a[i],l=max(l,a[i]);
    sort(a+1,a+1+n);
    while(l<r)
    {
        mid=(l+r)>>1;
        if(pd(mid))r=mid;else l=mid+1;
    }
    for(ans=l-50;ans<=l && !pd(ans);ans++);
    printf("%d",ans);
    return 0;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值