题意:
n个磁头去读取m个磁道,给出磁头和磁盘的初始位置(递增给出),问最少需要多少时间所有磁道均被读取。
思路:
二分答案还是很容易想到的,难点大概在于贪心。
在确定时间t后考虑:
由于有多个磁头,所有最左边的磁道肯定要由最左边的磁头去读取,但是如果没次都让磁头从左边开始读取,是不对的。最左边的磁道自然是要读取,但是贪心的思想下,我们应该让当前磁头在读取最左边的磁道的往右走的越远,因为这样就能在时间t以内读取更多的磁道。
当然还有一种情况是所有磁道都在当前最左边磁道的右边,那么直接往右走就好。
如果存在在左边的,那么当前磁头有两个选择,一种是先往右再往左,那么往右最多走(t-(h[i]-p[j]))/2的距离,第二种是先往左再往右,最多往右走t-2*(h[i]-p[j]),这个去最大值选择就行,依次这样跑h[i]。
另外需要注意的是时间t内如果无法到达最左边的磁头的话continue就行。
代码:
#include<bits/stdc++.h>
#define LL long long
using namespace std;
const int maxn=1e5+5;
LL h[maxn];
LL H[maxn];
LL o[maxn];
bool book[maxn];
int main()
{
int n, m;
cin>>n>>m;
int i, j;
for(i=0; i<n; i++)
{
scanf("%lld", &h[i]);
}
for(i=0; i<m; i++)scanf("%lld", &o[i]);
if(n==m)
{
for(i=0; i<m; i++)if(h[i]!=o[i])break;
if(i==m)return 0*printf("0\n");
}
long long r=1e15+5, l=1;
long long mid;
long long ans=0;
int s=0;
long long x;
for(int e=0; e<150; e++)
{
mid=(l+r)>>1;
s=0;
for(i=0; i<n; i++)
{
x=mid;
H[i]=h[i];
if(abs(H[i]-o[s])>mid)continue;
if(o[s]>=H[i])
{
for(j=s; j<m; j++)
{
if(o[j]-H[i]>mid)break;
}
s=j;
}
else
{
long long e=H[i]-o[s];
x=max(x-2*e, (x-e)/2);
for(j=s; j<m; j++)
{
if((o[j]-H[i])>x)break;
}
s=j;
}
if(s==m)break;
}
if(s==m)
{
r=mid-1;
ans=mid;
}
else
{
l=mid+1;
}
}
cout<<ans<<endl;
}