收集宝石

收集宝石(gem)

【题目描述】

         小R来到了一个神秘的房间,这个房间的地面上散落着n颗宝石,第i颗宝石的位置为(xi,yi),价值为wi。小R想要收集这些宝石,每颗宝石有一个收集范围,第i颗宝石的收集范围为ri,当小R离这颗宝石的距离在ri以内时,小R就可以收集到这颗宝石。现在小R在坐标原点,他可以使用一次闪现技能,瞬间闪现到距离R以内的一个整点A(即这个点的横纵坐标必须是整数),然后他可以收集到在点A能够收集到的所有宝石。由于某些原因,他在使用闪现技能前不能收集宝石。小R不能闪现到房间外面,房间一个由四条直线x=-w,x=w,y=-h,y=h组成的正方形。换句话说,小R只能闪现到横坐标在[-w,w]之间,纵坐标在[-h,h]之间的整点。

         小R希望收集到尽量多的宝石,但有时他不得不放弃一些宝石,他希望你告诉他,他至少需要放弃多少价值的宝石。并且他还想知道,他放弃这些价值的宝石时,他需要闪现到哪一个点。如果有多解,输出X坐标最小的;如果有多个解X坐标相等,输出Y坐标最小的解。

【输入格式】

         第一行4个整数R, n, w, h。

         以后N行,每行四个整数,分别表示xi,yi,wi,ri

【输出格式】

         输出分为两行。

         第一行一个整数,表示小R至少需要放弃多少价值的宝石

         第二行两个整数,小R应该闪现到的坐标。

【输入样例】

5 3 5 5

3 3 4 1

4 4 5 1

0 -2 7 1

【输出样例】

7

3 4

【输入样例】

5 3 3 3

3 3 4 1

4 4 5 1

0 -2 7 1

【输出样例】

9

-1 -2

【数据范围与约定】

对于100%的数据 N<=800 0<=Limit<=10^6,0<=W<=10000,0<=H<=10^6

数据序号

N

Limit

注释

1

<=5

<=100

 

2

<=12

<=10000

3

<=100

<=10000

随机数据

4

<=400

<=10^6

5

<=800

6

<=200

<=20000

 

7

8

<=400

<=10^6

9

10

所有输入都是整数,且绝对值不超过10^6

题解:我们注意到W比较小,所以直接暴力枚举W,对于每一条线上的圆所截的线段进行离散化,求出最小值。

Code:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstdlib>
#include<cstring>
using namespace std;
int R,n,w,h,len,all,num,x[10000],y[10000],W[10000],r[10000],ans,ansx,ansy,sum;
pair<int,int>a[1000005];
int main(){
	freopen("gem.in","r",stdin);
	freopen("gem.out","w",stdout);
	ans=-1000000000;
	scanf("%d%d%d%d",&R,&n,&w,&h);
	for(int i=1;i<=n;i++)scanf("%d%d%d%d",&x[i],&y[i],&W[i],&r[i]),all+=W[i];
	for(int i=-w;i<=w;i++){
		num=0;
		for(int j=1;j<=n;j++){
			if(abs(x[j]-i)>r[j])continue;
			len=int(sqrt((long long)r[j]*r[j]-(long long)(x[j]-i)*(x[j]-i)));
			a[++num]=make_pair(y[j]-len,W[j]);a[++num]=make_pair(y[j]+len+1,-W[j]);
		}
		a[++num]=make_pair(0,0);
		sort(a+1,a+1+num);
		sum=0;
		for(int j=1;j<=num;j++){
			sum+=a[j].second;
			if((long long)i*i+(long long)a[j].first*a[j].first>(long long)R*R||a[j].first>h||a[j].first<-h)continue;
			if(sum>ans){ans=sum;ansx=i;ansy=a[j].first;}
		}
	}
	printf("%d\n%d %d\n",all-ans,ansx,ansy);
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JackflyDC

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值