ZOJ - 3993(思维)

Safest Buildings

题目传送门
题意:吃鸡游戏,给出初始圈半径以及圈内的建筑,给你下一个圈的半径r(圈被要求在初始圈内),求最大概率为安全建筑的建筑有那几个。
思路:很简单可以知道,离中心越近越有可能,但事实上在某些范围内概率是相同的当r足够大或者足够小。我们把初始圈叫做大圆,下一个圈为小圆。当2*r大于R时,小圆内切大圆转一圈,可以发现以2*r-R为半径,以原圆心为圆心的圆内的点的安全概率为1即相等。当r<=R-r时,令P圆为小圆内切大圆时圆心围着大圆圆心形成的圆(即小圆圆心的可取范围),再令小圆内切p圆时圆心形成的圆为q圆,这时我们可以知道,q圆内的点的概率为1,(过一点画无数个半径为r的圆,以这些圆的圆心所形成的圆的面积/p圆的面积即为安全概率),而q圆内的圆的都可以形成面积相等的圆即安全概率相等。

#include <iostream>
#include <fstream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <stack>
#include <vector>
#include <map>
#include <set>
#include <cmath>
#include <algorithm>
#include <functional>
#define inf 0x7fffffff
using namespace std;
typedef long long ll;
const int MAXN=1e5+10;
const int MAX=1000+10;
const double eps=1e-6;

int n,R,r;
struct NODE{
    int x,y,id;
    ll dis;
}node[MAX];

int cmp(NODE a,NODE b){
    return a.dis<b.dis;
}

int main(){
    #ifdef ONLINE_JUDGE
    #else
    freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    #endif

    int T;
    cin>>T;
    while(T--){
        cin>>n>>R>>r;
        int ans=0,cnt=0;
        int s[MAX];
        for(int i=0;i<n;i++){
            scanf("%d%d",&node[i].x,&node[i].y);
            node[i].dis=(ll)node[i].x*node[i].x+(ll)node[i].y*node[i].y;
            node[i].id=i+1;
        }
        sort(node,node+n,cmp);
        if(2*r>=R){
            int d=2*r-R;
            d=d*d;
            for(int i=0;i<n;i++){
                if(node[i].dis<=d){
                    s[cnt++]=node[i].id;
                }
            }
        }
        else if(r<=R-r){
            int d=R-2*r;
            d=d*d;
            for(int i=0;i<n;i++){
                if(node[i].dis<=d){
                    s[cnt++]=node[i].id;
                }
            }
        }
        if(cnt==0){
            s[cnt++]=node[0].id;
            for(int i=1;i<n;i++){
                if(node[i].dis==node[0].dis){
                    s[cnt++]=node[i].id;
                }
            }
        }
        sort(s,s+cnt);
        cout<<cnt<<endl;
        for(int i=0;i<cnt;i++){
            if(i==0)
                cout<<s[i];
            else
                cout<<" "<<s[i];
        }cout<<endl;
    }

    return 0;   
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值