首页 > 其他分享 >P3897 [湖南集训] Crazy Rabbit

P3897 [湖南集训] Crazy Rabbit

时间:2023-12-02 19:56:07浏览次数:33  
标签:Crazy angle int double P3897 leq Rabbit 区间 define

[湖南集训] Crazy Rabbit

Luogu P3897

题目描述

兔子们决定在自己的城堡里安排一些士兵进行防守。

给出 \(n\) 个点的坐标,和城堡里一个圆心在原点的圆形的障碍,兔子们希望从中选出 \(k\) 个兔子,使得它们两两所在的直线都不与圆相交。

兔子们希望知道最多能选出多少兔子。

  • 对于 \(10\%\) 的数据,保证 \(1\leq n\leq 20\)。
  • 对于 \(30\%\) 的数据,保证 \(1\leq n\leq 100\)。
  • 对于 \(100\%\) 的数据,保证 \(1\leq n\leq 2000\),\(1\leq r,x_i,y_i \leq 5000\)。

Solution

考虑对于每个点作出对圆的两条切线,那么每一个点都可以对应成圆上的一个区间。具体的区间可以使用 atan2acos 计算出来。

考虑这一个转化有什么作用。观察发现,如果两个点可以同时选,那么这两个点对应的区间一定是相交且不是包含关系。容易证明这是充要条件。

那么问题转化成为了选出尽可能多的区间,使得所有区间两两相交且不包含。观察数据范围发现可以枚举一个起点区间,然后剩下的计算只要能在 \(\mathcal O(n\log n)\) 内完成都是可行的。

考虑枚举起点区间,然后将所有左端点在起点区间内,右端点不在起点区间内的区间取出。将这些区间按照左端点排序,那么因为不能存在包含关系,那么此时能选择的区间的右端点应该是递增的。也就是选定了起点区间并将其他区间按照上述规则排序后只需要求右端点的 LIS 即可算出答案。那么 \(\mathcal O(n^2\log n)\) 的做法显然。

由于原问题的区间是在一个圆上的,因此需要确定一个分割点。考虑跨过分割点的区间如何处理。会发现如果将这个区间变成其在圆上的补集不会导致答案变化。

代码上细节有点多,需要仔细实现。

Code
// Cirno is not baka!
#include <bits/stdc++.h>
#define For(i, a, b) for (int i = (a); i <= (int)(b); ++i)
#define Rof(i, a, b) for (int i = (a); i >= (int)(b); --i)
#define Debug(...) { \
    fprintf(stderr, "Function{%s},line[%d]:\t", __FUNCTION__, __LINE__); \
    fprintf(stderr, __VA_ARGS__); \
    fprintf(stderr, "\n"); \
}
#define FILE(filename) { \
    freopen(#filename ".in", "r", stdin); \
    freopen(#filename ".out", "w", stdout); \
}
#define All(x) x.begin(), x.end()
#define rAll(x) x.rbegin(), x.rend()
#define pii pair<int, int>
#define fi first
#define se second
#define i64 long long
#define mkp make_pair
// #define int long long
using namespace std;

const int _N = 1e6 + 5, mod = 1e9 + 7;
template<typename T> void Max(T &x, T y) {x = max(x, y);}
template<typename T> void Min(T &x, T y) {x = min(x, y);}
template<typename T1, typename T2>
void Addmod(T1 &x, T2 y) {x += y; x >= mod ? x -= mod : x;}
template<typename T1, typename T2>
T1 Add(T1 x, T2 y) {x += y; return x >= mod ? x - mod : x;}

namespace BakaCirno {
    const double PI = acos(-1), inf = 1e18;
    int N, radiu;
    struct Vec2 {
        int x, y;
        Vec2(int x = 0, int y = 0) : x(x), y(y) {}
        double operator() () {return sqrt(1. * x * x + 1. * y * y);}
    } P[_N];
    vector<pair<double, double>> vec;
    void Solve() {
        cin >> N >> radiu;
        For(i, 1, N) {
            cin >> P[i].x >> P[i].y;
            double mid = atan2(P[i].y, P[i].x);
            double angle = acos(radiu / P[i]());
            double L = mid - angle, R = mid + angle;
            auto Mod = [](double &angle) {
                while (angle < 0) angle += 2 * PI;
                while (angle >= 2 * PI) angle -= 2 * PI;
            };
            Mod(L), Mod(R);
            if (L > R) swap(L, R);
            vec.emplace_back(L, R);
            assert(L >= 0 && L <= 2 * PI);
            assert(R >= 0 && R <= 2 * PI);
        }
        sort(vec.begin(), vec.end());
        auto Calc = [](const vector<double> &A)->int {
            static double f[_N]; int len = 0;
            For (i, 0, A.size() - 1) {
                *upper_bound(f + 1, f + len + 1, A[i]) = A[i];
                if (f[len + 1]) ++len;
            }
            For(i, 0, len) f[i] = inf;
            return len;
        };
        int ans = 0;
        For(i, 0, N - 1) {
            vector<double> cur;
            cur.emplace_back(vec[i].se);
            For(j, i + 1, N - 1)
                if (vec[j].fi <= vec[i].se && vec[j].se >= vec[i].se)
                    cur.push_back(vec[j].se);
            ans = max(ans, Calc(cur));
        }
        cout << ans << '\n';
    }
}

signed main() {
    // FILE(test);
    cin.tie(0)->sync_with_stdio(0); int T = 1;
    // cin >> T;
    while (T--) BakaCirno::Solve();
}

标签:Crazy,angle,int,double,P3897,leq,Rabbit,区间,define
From: https://www.cnblogs.com/hanx16msgr/p/17872126.html

相关文章

  • RabbitMQ 发送消息到交换机
    发送消息到交换机的代码:@GetMapping("/mq02")//发送消息给交换机publicvoidmq02(){StringexchangeName="hmall.fanout";Stringmsg="hello,每个人";//三个参数:交换机名称、RoutingKey(暂时为空)、要发送的消息rabbitTemplate.convertAndSend(exchangeName,......
  • RabbitMQ Fanout交换机
     容易搞混的点:1.假如publisher给Fanout交换机发送了一条消息,那么Fanout交换机会给每一个绑定到它身上的队列都发送这条消息,也就是说有多少个队列跟它绑定了,这条消息就有几份,每个队列都收到一份。2.假如一个队列绑定了多个消费者,那么该队列在给消费者投递消息时就是轮询,一......
  • rabbitmq的推(push)拉(pull)模式介绍及代码实现
    在rabbitmq中有两种消息处理的模式,一种是推模式/订阅模式/投递模式(也叫push模式),消费者调用channel.basicConsume方法订阅队列后,由RabbitMQ主动将消息推送给订阅队列的消费者;另一种是拉模式/检索模式(也叫pull模式),需要消费者调用channel.basicGet方法,主动从指定队列中拉取消息。推......
  • RabbitMQ work模型
    默认情况下,MQ队列如果绑定了多个消费者,那么队列在投递消息时就是轮询,一人投递一个(并且一条消息只能投递给监听该队列的某一个消费者)在一个MQ队列上绑定多个消费者的目的是加快队列中消息的处理效率,防止队列中消息的堆积问题。 注:要在消费者的application.yml文件中加上这个......
  • RabbitMQ 接收队列的消息
     代码示例:注:要把这个类加上Component注解packagecom.itheima.amqp_listener;importorg.springframework.amqp.rabbit.annotation.RabbitListener;importorg.springframework.stereotype.Component;@ComponentpublicclassMQListener{@RabbitListener(queues="simpl......
  • RabbitMQ 发送消息到队列(交换机不参与的那种)
    1.导包<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifactId></dependency>2.在application.yml文件里编写配置信息spring:rabbitmq:host:192.168.88.130port:5672......
  • 【Spring】SpringBoot+RabbitMQ(direct/fanout/topic)の構築方法
     ■POM.xmlの中で、下記の内容を追加<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifactId></dependency><dependency>......
  • 使用RabbitMQ时使用MemoryPack序列化和反序列化对象
    [MemoryPackable]publicpartialclassUserEto{publicStringName{get;set;}} 发送端publicclassEventBus:IEventBus{publicvoidPublish(stringexchangeName,objecteventData){usingvarconnection=RabbitMQ......
  • RabbitMQ消息队列
    一.什么是消息队列1.简介在介绍消息队列之前,应该先了解什么是AMQP(AdvancedMessageQueuingProtocol,高级消息队列协议,点击查看)消息(Message)是指在应用间传送的数据,消息可以非常简单,比如只包含文本字符串,也可以更复杂,可能包含嵌入对象;而消息队列(MessageQueue)是一种应用间的......
  • 【MQ】RabbitMQの概念紹介及び実行方法
    参考URL:<https://www.cnblogs.com/yy-cola/p/11089800.html><https://blog.csdn.net/qq_41097820/article/details/88793329>■中心概念【Message】消息消息是不具名的,它由消息头和消息体组成,消息体式不透明的,而消息头则由一系列的可选属性组成,这些属性包括routing-key(路由......