加载中...

SDTBU-ACM集训队暑期集训---个人赛 14


前言

看了看舍友写的,很优雅,发现有些时候虽然可以交的上去,但是不同思路的代码长度差距非常之大。

另外第一题想遍历数组的,应该写成a[j]写成了j,调试了半天才看出来。第二题被调函数传错数了,连WA11次,陷入了深深自我怀疑,有点小小难受。

第一题

题目: Light It Up

题意:

在x-y的坐标轴上有n个人分别坐在不同的点上,其中有k个人坐的地方有一盏灯,每盏灯可以照亮半径为r的圆。要求我们求出所有人都被照亮时,如果所有灯的半径相同,那么最小可以是多少。

输入格式

第一行是两个整数n和k。

第二行是k个整数,表示所在位置有灯的人的序号。

第三行到n+2行,每行只有两个整数(xi,yi)表示序号为i的人所在的位置。

输出格式

输出一个实数,表示灯的最小半径。要求结果误差小于-105

数据范围

1 ≤ K < N ≤ 1000

1 ≤ A1 < A2 < ⋯ < AK ≤ N

∣Xi∣, ∣Yi∣ ≤ 105

保证每个点只会有一个人。

输入样例:

4 2
2 3
0 0
0 1
1 2
2 0

输出样例:

2.23606797749978969

思路:

  • 贪心。题目要求我们找到当所有人都被覆盖时,灯的最小半径。
  • 首先我们必须满足每个人都被至少一个灯的半径覆盖,那么可以先遍历所有人,然后对每个人遍历所有灯,对每个人维护人和其它灯距离的最小值。最后再排一次序,输出所有人的距离最大值就好了。
  • 为什么是最大值?因为要满足所有人都被照到,我们维护的距离是当前这个人距离其它灯的最小值,那么所能接受距离的最低限度就是所有最小距离中的最大值。

代码:

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<algorithm>
#include<unordered_map>
#include<cstring>
#include<vector>

using namespace std;

const int N = 1e3 + 10;
#define long long LL;

int a[N];
pair<int, int>p[N];
double b[N];

double slove(int i, int j)
{
	int x = abs(p[j].first - p[i].first);
	int y = abs(p[j].second - p[i].second);
	return (double)sqrt((double)x*x+(double)y*y);
}

int main()
{
	int n, k;
	cin >> n >> k;
	for (int i = 1; i <= k; ++i) cin >> a[i];
	for (int i = 1; i <= n; ++i)cin >> p[i].first >> p[i].second;

	//遍历每个人,找到每个人被照到的最小范围,然后在所有范围中找到最大的
	for (int i = 1; i <= n; ++i)
	{
		b[i] = 1e9;
		for (int j = 1; j <= k; ++j)
			b[i] = min(b[i], slove(i,a[j]));
	}

	sort(b + 1, b + n + 1);

	printf("%.12lf\n", b[n]);

	return 0;
}

第二题

题目: ±1 Operation

题意:

给我们四个数X,A,D,N,其中A,D,N组成一个首项为A,公差为D,共有N项的等差数列。每次可以将X的值加一或者减一,求解最少几次可以将X变为该等差数列中的一项。

输入格式

输入只有四个整数:X,A,D,N

输出格式

一个整数,表示对X的操作次数。

数据范围

−1018 ≤ X, A ≤ 1018

−106 ≤ D ≤ 106

1 ≤ N ≤ 1012

输入样例:

-555555555555555555 -1000000000000000000 1000000 1000000000000

输出样例:

444445

思路:

  • 我们可以设B为该等差数列的尾项,如果X小于首项或者大于尾项,那么操作次数分别是X和首项或尾项差的绝对值。
  • 如果X的值在该数列首尾两项之间,由于数据范围极大,暴力循环是一定会超时的,所以考虑二分。
  • 需要注意的是在进行二分时,需要考虑D的符号问题,要将A和B的值互换,同时不要忘记将D的值取反。

代码:

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<algorithm>
#include<unordered_map>
#include<cstring>
#include<vector>

using namespace std;

const int N = 1e3 + 10;
#define LL long long 

//给我们一个数字x,让我们用最少的操作次数将x变为一个好数字
//好数字定义:有一个n项的数列s,s1=a,公差为d

void slove(LL x, LL a, LL d, LL n, LL b)
{
	if (x <= a)
		cout << a - x;
	else if (x >= b)
		cout << x - b;
	else
	{
		LL l = 0, r = n - 1;
		while (l < r)//找到第一个大于等于x的数。
		{
			LL mid = (l + r) / 2;
			if ((mid * d + a) >= x) r = mid;
			else l = mid + 1;
		}

		LL k1 = (l * d + a)-x;
		LL k2 = x - ((l - 1) * d + a);
		cout << min(k1,k2);
	}
}

int main()
{
	LL x, a, d, n;
	cin >> x >> a >> d >> n;

	LL b = a + d * (n - 1);
	if (d >= 0) slove(x, a, d, n, b);
	else slove(x, b, -d, n, a);

	return 0;
}

文章作者: 心意
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 心意 !
评论
  目录