XJOI xtx的游戏(计算几何)

题意非常清真,给你一堆点和一个圆半径,选一个圆心让覆盖的点的点权和最大

首先,傻傻的做法,暴力微分枚举点,暴力统计答案.玄学复杂度

这个傻傻的代码虽然不是重点,还是贴一张图片吧

然后开始糊正解,正解,正解!

思考一个圆覆盖的点集,肯定可以通过某种变换让两个点在圆上且包含的点不变

分类讨论:

1.两个点刚开始就在圆上

2.一个点在圆上,绕该点旋转圆,第一个点碰到边界时停下,转化为1

3.无点在圆上,先平移,第一个点碰到边界时停下,转化为2

于是,上述结论证明了.

/-----------------------------------------------/

那么只需要枚举两个点,因为知道半径,所以就可以算出两个圆心作为候选答案,然后暴力统计答案即可

复杂度n^3

/-----------------------------------------------/

然而,我却没有用这种方法,而是学习了zrf的方法,因为这种方法更好写且复杂度更优,仅为n^2logn,

首先,思考一个圆覆盖的点集,肯定可以通过某种变换让至少一个点在圆上且包含的点不变

这就不证明了,跟上面的证明如出一辙

那么就先枚举这个点

再使用扫描线做法,统计出每个可能被覆盖的点开始被覆盖的弧度和离开圆的弧度,然后排一遍序,一边扫过去统计答案.

如图

然后就非常简单了

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=210;
const double pi=3.14159265358979323,eps=1e-12;
struct vec{
    double x,y;
    inline vec(double x=0,double y=0):x(x),y(y){};
}a[N];
inline vec operator -(vec x,vec y){
    return vec(x.x-y.x,x.y-y.y);
}
inline double dot(vec x,vec y){
    return x.x*y.x+x.y*y.y;
}
inline int dcm(double x,double y){
    return fabs(x-y)<eps?0:x>y?1:-1;
}
vector<pair<double,int> >g;
int n,w[N];
double r;
ll ans;
ll solve(const int x){
    g.clear();
    ll res=0,ttt=0;
    for (int i=1; i<=n; i++)
    if (i!=x){
        vec t=a[i]-a[x];
        double dis=sqrt(dot(t,t)),now,oth;
        if (dcm(dis,2*r)==1) continue;
        now=atan2(t.y,t.x);
        oth=acos(dis/(2*r));
        g.push_back(make_pair(now-oth,w[i]));
        g.push_back(make_pair(now+oth,-w[i]));
    }
    sort(g.begin(),g.end());
    for (vector<pair<double,int> >::iterator it=g.begin(); it!=g.end(); it++){
        ttt+=(*it).second;
        res=max(res,ttt);
    }
    return res+w[x];
}
int main(){
    scanf("%lf%d",&r,&n);
    for (int i=1; i<=n; i++) scanf("%lf%lf%d",&a[i].x,&a[i].y,&w[i]);
    for (int i=1; i<=n; i++) ans=max(ans,solve(i));
    printf("%lld",ans);
}

/------------------------------------------------/

但是还有一个事情没有说,

那就是彩蛋

那就是atan2函数

atan2(double y,double x)是系统自带的,精度比atan要好很多(注意是先y后x)

因为他计算时如果fabs(x)>fabs(y)那么算的时候就会使用atan(y/x)而不是atan(x/y)

然而他又不完全等于atan

他的返回值在(-pi,pi)之间

那么是什么含义呢

那就是原点向右的水平向量作为始边(x轴)

以逆时针为正方向

原点出发的向量(x,y)作为终边的角度值

于是,这玩意是极角排序神器,不仅精度高,而且方便

比如说,你要对n个点进行极角排序,可以不用差积,任意选一个点作为一个原点直接按照atan2值排序

就得到了第三象限->第四象限->第一象限->第二象限的一个序列

时间: 2024-10-10 15:37:58

XJOI xtx的游戏(计算几何)的相关文章

BZOJ 1199: [HNOI2005]汤姆的游戏 计算几何暴力

1199: [HNOI2005]汤姆的游戏 Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline/problem.php?id=1199 Description 汤姆是个好动的孩子,今天他突然对圆规和直尺来了兴趣.于是他开始在一张很大很大的白纸上画很多很多的矩形和圆.画着画着,一不小心将他的爆米花弄撒了,于是白纸上就多了好多好多的爆米花.汤姆发现爆米花在白纸上看起来就像一个个点,有些点落在矩形或圆

BZOJ 1199 HNOI2005 汤姆的游戏 计算几何+暴力

题目大意:给定n个图形,每个图形可以是矩形或圆,m次询问某个点在多少个图形内部 将点按横坐标排序 对于每个图形,二分找到x值满足要求的区间,对于区间内每个点暴力 时间复杂度O(n^2) 数据范围25W 果然像hwd说的一样计算几何题数据范围出的这么大就是作死么= = #include <cmath> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm&

vijos 1288 箱子游戏 计算几何

背景 hzy是箱子迷,他很喜欢摆放箱子,这次他邀请zdq,skoier一起来玩game... 描述 地板上有一个正方形的大箱子和许多三角型的小箱子.所有的小箱子都在大箱子里面,同时,一些三角形的小箱子可能在另一些小箱子里面,但是所有的小箱子都不相交.你在大箱子里面随机选一个点,它恰好在inBox个小箱子里的概率是多少?我们知道,大箱子的边都平行于坐标轴,并且有两个顶点位于(0,0)和(100,100). 格式 输入格式 输入的第一行包含两个正整数n和inBox(0 <= inBox <= n

XJOI xtx的旅行(状压+spfa)

这题是一道状压加spfa,考试的时候我非常naive地写了一个复杂度为O(4^p)*O(n+m)的暴力,因为复杂度上界比较松,就卡着评测机水过了.(2000+ms) 但是这题仅仅那样做非常不科学,非常慢,也可以被卡掉时间. 于是,我请教了旁边的cxt(%%%%) cxt对我说到达一个点以及一个状态后,可以分开买物品和走路,这非常有道理,因为买物品和走路是互不影响的,这样上界就是O(2^p)*O(n+m) 于是,我贯彻cxt的思想,写了一个自认为很高妙的程序,跑了500ms+. 但是,cxt看了我

BZOJ 1199 HNOI 2005 汤姆的游戏 计算几何

题目大意 给出若干个图形,这些图形中有些是矩形,剩下的是圆形.还有一些点,问每个点在多少个图形里面. 思路 题目没写数据范围,其实是25w.敢O(n^2)暴力么?没错这个题就是暴力.只需用二分处理一维坐标然后第二维暴力就行了. CODE #define _CRT_SECURE_NO_WARNINGS #include <cmath> #include <cstdio> #include <cstring> #include <iostream> #inclu

XJOI 游戏

题目大意: Alice和Bob两个人正在玩一个游戏,游戏有很多种任务,难度为p的任务(p是正整数),有1/(2^p)的概率完成并得到2^(p-1)分,如果完成不了,得0分.一开始每人都是0分,从Alice开始轮流做任务,她可以选择任意一个任务来做:而Bob只会做难度为1的任务.只要其中有一个人达到n分,即算作那个人胜利.求Alice采取最优策略的情况下获胜的概率. 数据范围: n<=500 (本题输出小数即可) 这题正解是概率dp 设f[i][j]表示Alice此时i分,Bob此时j分,Alic

XJOI游戏

Description 暑假到了,次方又可以打网络游戏了.然而在一堆玩家中选择哪些人来刷副本可是一件伤脑筋的事.现在有n个人,如果同时选择了i和j这两个人,则会产生Aij的战斗力加成.但是如果一共选择了k个人,那么会造成k*(200-k)的网络延迟.团队的总战斗力定义为所有人之间的战斗力加成的和/总的网络延迟.次方想知道能得到的最大的战斗力是多少. Input 第一行,一个整数n,表示总人数.下面n行,每行n列,第i行第j列的元素Aij(0<=Aij<10)表示同时选择i和j带来的战力加成.(

【计算几何】【斜率】bzoj1610 [Usaco2008 Feb]Line连线游戏

枚举直线,计算斜率,排序,统计答案. #include<cstdio> #include<cmath> #include<algorithm> using namespace std; #define EPS 0.00000001 #define INF 99999999999999999999.0 #define N 201 typedef double db; int n,m,sta,ans; db xs[N],ys[N],line[N*N]; int main()

拼接游戏(线段树、计算几何)

题目大意: 给出一段由N个线段首尾相接而成的绳子,其中第 i 条线段(从1开始)是由点 Pi-1 和 点 Pi 相连而成,一开始绳子从原点向y轴正方向延伸,现在要对绳子做M次修改,每次修改会把第u + 1条线段调整到第u条线段逆时针方向w度的位置,其他线段之间的关系不变,要求输出每次修改后点 PN 的坐标. 输入:第一行N,M(N,M <= 10000):第二行N个整数,表示这些线段的长度(长度为1-99之间的整数):接下来M行每行两个整数u,w(0 < u < N,0 <= w