第二周
第一题
题目1
多次查找一组有序数中指定数的最小编号
思路1
数据量较大且有序,二分查找。
通过判断区间中间值与指定数的大小来快速缩小区间。
代码1
#include<cstdio>
//存储序列
int number[1000001];
//存储要找的数
int numberToFind[100001];
int main()
{
//数字个数和询问次数
int n, m;
//读
scanf("%d %d", &n, &m);
for(int i = 1; i <= n; i++)
{
scanf("%d", &number[i]);
}
for(int i = 1; i <= m; i++)
{
scanf("%d", &numberToFind[i]);
}
//查
for(int i = 1; i <= m; i++)
{
//找到的编号
int p = 0;
//左边界和右边界
int l = 1, r = n;
//二分
while(l <= r)
{
//区间中间
int mid = (l + r) / 2;
//如果找到了
if(number[mid] == numberToFind[i])
{
//记录
p = mid;
//缩小到左半区间查找是否有更小的编号
r = mid - 1;
}
//如果中间数字小,就缩小到右半区间
else if(number[mid] < numberToFind[i])
{
l = mid + 1;
}
//如果中间数字小,就缩小到左半区间
else
{
r = mid - 1;
}
}
//p是0就代表没找到
if(!p)
{
printf("-1 ");
}
else
{
printf("%d ", p);
}
}
return 0;
}
第二题
题目2
有N个隔间的牛棚,把C头牛安置在指定的隔间,所有牛中相邻两头的最近距离越大越好,求最大的最近距离。
思路2
可以容易地判断出某个数是不是答案,所以可以通过类似二分查找的二分答案的方法来得到答案
代码2
#include<iostream>
#include<algorithm>
using namespace std;
//隔间的位置
int room[100001];
int n, c;
bool check(int d)
{
//能放得下的牛的数量
int sum = 1;
//当前的位置
int p = 1;
for(int i = 2; i <= n; i++)
{
//如果距离够
if(room[i] - room[p] >= d)
{
//数量加一
sum++;
//更新位置
p = i;
}
}
//放得下
if(sum >= c)
{
return true;
}
//放不下
else
{
return false;
}
}
int main()
{
cin>>n>>c;
for(int i = 1; i <= n; i++)
{
cin>>room[i];
}
//对隔间的位置排序
sort(room + 1, room + n + 1);
//左界、右界、最大的距离
int l = 1, r = 1000000000, maxd;
//二分
while (l <= r)
{
//中间值
int mid = (l + r) / 2;
//如果符合,就查找右半区间是否有更大值
if(check(mid))
{
//记录
maxd = mid;
l = mid + 1;
}
//否则查找左半区间
else
{
r = mid - 1;
}
}
cout<<maxd<<endl;
return 0;
}
第三题
题目3
两块岩石作为比赛起点和终点,在起点和终点之间,有N块岩石。移走一些岩石,使得选手们在比赛过程中的最短跳跃距离尽可能长。求最短跳跃距离的最大值。
思路3
类似第二题,同样可以通过二分答案来找到答案。
代码3
#include<iostream>
using namespace std;
//记录石头间距离
int rock[50003];
//总长度,石头数,最多移走石头数
int length, n, m;
//判断答案是否符合
bool check(int d)
{
//需要移走的石头数
int sum = 0;
//当前位置
int p = 1;
//模拟跳跃
for(int i = 2; i <= n + 2; i++)
{
//如果距离太短,就移走石头
if(rock[i] - rock[p] < d)
{
sum++;
}
else
{
//更新位置
p = i;
}
}
//如果需要移走数多于指定数,则不符合
if(sum > m)
{
return false;
}
//符合
else
{
return true;
}
}
int main()
{
cin>>length>>n>>m;
for(int i = 2; i <= n + 1; i++)
{
cin>>rock[i];
}
//第一块石头是起点石头
rock[1] = 0;
//最后一块石头是终点石头
rock[n + 2] = length;
//左界、右界、最大距离
int l = 1, r = length, maxd;
//二分
while (l <= r)
{
//中间值
int mid = (l + r) / 2;
//如果符合
if(check(mid))
{
//记录
maxd = mid;
//继续在右半区间寻找更大的解
l = mid + 1;
}
else
{
//在左半区间寻找解
r = mid - 1;
}
}
cout<<maxd<<endl;
return 0;
}