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;
}