读
【问题背景】
zhx 为他的妹子制造了一个特别的图灵机(的磁带) 。
【问题描述】
有一个两端无限长的磁带,有N 个读取指针在某些位置,需要读取 M 个位置上的数据。每一个单位时间每个读取指针都可以向左或向右移动一格。如果存在某个时刻某个读取指针在某一个位置上(包括0时刻),那么这个位置上
的数据就会被读取。(注意,不需要读取的位置也能被指针经过)
zhx 去陪妹子了,现在你需要帮他解决一个问题,最少经过多少时间,M个需要读取的位置都能被读取?
【输入格式】
第一行两个整数N,M,表示指针数和需要读取的位置数。
接下来一行N 个整数,a " 表示第 i 个指针初始位置。
接下来一行 M 个整数,b " 表示第 i 个需要读取的位置。
【输出格式】
一行一个整数,代表需要的最小时间。
【样例输入】
3 4
2 5 6
1 3 6 8
【样例输出】
2
【样例输入】
3 3
1 2 3
1 2 3
【样例输出】
0
分析: 正解没想出来,直接打的暴力50分,TLE 正解竟然是二分,万万没想到。想来也满足二分答案的性质,二分出答案后,接下来是 判断答案是否行得通:采用贪心的思想,用靠前的指针尽量指向靠前的目标。 代码: #include<cstdio> #include<iostream> #include<cstdlib> #define N 100010 #define ll long long #define INF 10000000000000LL using namespace std; ll a[N],b[N],belong[N],n,m,ans=INF; ll read() { ll num=0,flag=1;char c=getchar(); while(c<'0'||c>'9'){if(c=='-')flag=-1;c=getchar();} while(c>='0'&&c<='9'){num=num*10+c-'0';c=getchar();} return num*flag; } bool check(ll mid) { for(ll i=1,j=1;i<=n;i++) { if(a[i]-b[j]>mid)return false; ll reach; if(b[j]<a[i]) { ll rest=mid-(a[i]-b[j]); reach=max(b[j]+rest,a[i]+rest/2); } else reach=a[i]+mid; while(b[j]<=reach&&j<=m)j++; if(j>m)return true; } return false; } int main() { //freopen("jh.in","r",stdin); freopen("read.in","r",stdin); freopen("read.out","w",stdout); n=read();m=read(); for(ll i=1;i<=n;i++)a[i]=read(); for(ll j=1;j<=m;j++)b[j]=read(); ll l=0,r=INF,ans; while(l<=r) { ll mid=(l+r)/2; if(check(mid)) { r=mid-1; ans=mid; } else l=mid+1; } cout<<ans; return 0; }