Distinct
题目
Daniel 正在玩一个战棋游戏。
现在 Daniel 有 n 队士兵站在 x 轴上。第 i 队士兵有 ai 人,坐标为 xi。
Daniel 看到一队士兵有这么多人,都站在同一个位置,他对此很不满意。他
想命令一些士兵移动到新的位置(必须是整点),使得不存在两个士兵站在同一个
位置。
为了节约时间,Daniel 希望每个士兵的移动距离的最大值尽可能小。请求出
这个最小值。
输入
第一行一个正整数 n,表示 Daniel 有多少队士兵。第二行 n 个正整数 ai,表示每队士兵的人数。第三行 n 个严格递增的 整数 xi,表示每队士兵的坐标。
输出
一行一个非负整数,表示每个士兵的移动距离的最大值的最小值
输入样例
2
2 3
0 2
输出样例
1
样例说明
移动后,5 个士兵的坐标分别为 -1, 0, 1, 2, 3。
有 2 个士兵移动距离为 0,3 个士兵移动距离为 1,因此答案是1
数据范围
思路
这道题我们可以用二分来做。
但是,怎么判断在哪边呢?
我们可以让每队士兵尽量往左,然后判断是否超过下一队往右可以到的位置,如果超过了,答案就在右边(走的还不够远),否则就在左边(走的够远了)。
代码
#include<cstdio>
#include<algorithm>
#include<iostream>
using namespace std;
struct note
{
int a,b;
}a[100001];
int n,l,r;
bool pd(int mid)
{
int now=a[1].b-mid+a[1].a;//第一队士兵尽可能向左移
if (now-1>a[1].b+mid) return 0;//判断是否超过下一队
for (int i=2;i<=n;i++)
{
now=max(now,a[i].b-mid)+a[i].a;//如果尽可能向左移,如果更上一对有交差就要从上一支队开始
if (now-1>a[i].b+mid) return 0;//判断是否超过下一队
}
return 1;
}
bool cmp(note x,note y)//按坐标把士兵从小到大排序
{
return x.b<y.b;
}
int main()
{
scanf("%d",&n);//读入
for (int i=1;i<=n;i++)
{
scanf("%d",&a[i].a);//读入
r+=a[i].a;//求出要二分答案的最大值
}
for (int i=1;i<=n;i++) scanf("%d",&a[i].b);//读入
sort(a+1,a+n+1,cmp);//按坐标把士兵从小到大排序
while (l<=r)
{
int mid=(l+r)/2;//找出中间值
if (pd(mid)) r=mid-1;//答案在左边
else l=mid+1;//答案在右边
}
printf("%d",l);
return 0;
}