收集宝石(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;
}
标签:宝石,收集,int,闪现,long,num From: https://blog.51cto.com/u_15888102/5878351