列表

详情


NC202505. 工具人

描述

疫情当前,为了给国家做贡献,牛能一直宅在家里
为了排遣寂寞,他打开了一款叫做《消灭病毒》的游戏
游戏种牛能有一把激光枪,射谁谁死,誓要把病毒消灭光
成为了一个无情无义的灭病毒工具
但是由于前期太过放肆,不懂得节省弹药,快要弹尽人亡了
为了等待援军的到来,他必须节约现在的每一发弹药
若把地图看作直角坐标系,牛能就在原点固守待援
已知本轮病毒的具体位置,并且若病毒距离牛能激光射线的距离不大于d就会被消灭
你能否求出牛能最少开几枪,才能把本轮的病毒消灭干净

输入描述

第一行输入一个,代表数据的组数
每组数据第一行输入两个正整数
n是病毒的个数,d含义如题
接下来每行给出一个坐标
保证x,y不会同时为零

输出描述

对于每组输入在一行中输出最少的开枪次数

示例1

输入:

1
7 1
-1 -4
-3 1
-3 -1
2 3
2 4
2 -2
6 -2

输出:

4

说明:

示例2

输入:

1
4 0
0 4
-12 18
0 27
-34 51

输出:

2

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++(clang++11) 解法, 执行用时: 57ms, 内存消耗: 432K, 提交时间: 2020-12-01 13:15:20

#include <bits/stdc++.h>
using namespace std;

const int N = 2e5 + 100;

struct node {
	int w;
	double ang;
	int id;
	bool operator<(const node &M) const {
		if (fabs(ang - M.ang) < 1e-12)
			return w < M.w;
		return ang < M.ang;
	}
} e[N];


bool vis[1010];
int main() {
	int T;
	cin >> T;
	while (T--) {
		int n, d;
		cin >> n >> d;
		int cnt = 0;
		int id = 0;
		for (int i = 1; i <= n; i++) {
			double x, y;
			cin >> x >> y;
			if (x * x + y * y <= d * d + 1e-12)
				continue;
			double ang = atan2(y, x);
			double a = asin(1.0 * d / sqrt(x * x + y * y));
			id++;
			e[cnt++] = {0, fmod(ang - a + 4 * acos(-1), 2 * acos(-1)), id};
			e[cnt++] = {1, fmod(ang + a + 4 * acos(-1), 2 * acos(-1)), id};
		}

		if (cnt == 0)
			puts("1");
		else {
			sort(e, e + cnt);
			int ans = id;
			for (int i = 0; i < cnt; i++) {
				int num = 0;
				memset(vis, 0, sizeof vis);
				vector<int>vec;
				vec.clear();
				for (int k = 0; k < cnt; k++) {
					int j = (i + k) % cnt;
					if (e[j].w == 0) {
						vis[e[j].id] = 1;
						vec.push_back(e[j].id);
					}
					if (e[j].w == 1 && vis[e[j].id]) {
						num++;
						for (auto it : vec)
							vis[it] = 0;
						vec.clear();
					}
				}
				num += vec.size();
				ans = min(ans, num);
			}
			cout << ans << endl;
		}
	}
	return 0;
}

C++14(g++5.4) 解法, 执行用时: 20ms, 内存消耗: 480K, 提交时间: 2020-03-03 23:04:44

#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
using namespace std;
struct node {
	double x,y,l,r;
} p[505];
inline bool cmp(node a,node b) {
	return a.l<b.l;
}
const double pi=acos(-1);
double pl[505],pr[505],maxr[505],r;
int main() {
	int n,T,cnt,cnt2,ans,pos,tot;
	double d,dis,si,otg,t,tg;

	scanf("%d",&T);
	while(T--) {

		scanf("%d%lf",&n,&d),cnt=0;
		for (int x,y,i=1; i<=n; i++) {
			scanf("%d%d",&x,&y);
			dis=sqrt(x*x+y*y);
			if (dis<=d) continue;

			si=d/dis,otg=si/sqrt(1-si*si);
			t=atan(otg),tg=atan2(y,x);

			while(tg-t<0) tg+=2*pi;
			while(tg-t>2*pi) tg-=2*pi;
			p[++cnt]=(node) {
				x,y,tg-t,tg+t
			};
		}

		sort(p+1,p+cnt+1,cmp);

		if (cnt) {
			ans=cnt;
			for(int i=1; i<=cnt; i++) {
				cnt2=0;

				for (int j=i; j<=cnt; j++)
					pl[++cnt2]=p[j].l,pr[cnt2]=p[j].r;
				for (int j=1; j<i; j++)
					pl[++cnt2]=p[j].l+2*pi,pr[cnt2]=p[j].r+2*pi;

				pos=1,tot=0,maxr[cnt]=pr[cnt];
				for (int j=cnt-1; j; j--) maxr[j]=min(maxr[j+1],pr[j]);
				while(pos<=cnt) {

					r=maxr[pos];
					while(pos<=cnt && pl[pos]<=r) pos++;
					tot++;
				}
				ans=min(ans,tot);
			}
			printf("%d\n",ans);
		} else puts("1"); //由于病毒数n>=0,如果病毒到圆心距离<=d,至少需要一条直线
	}
}

上一题