[LOJ#6437][BZOJ5373]「PKUSC2018」PKUSC

试题描述

九条可怜是一个爱玩游戏的女孩子。

最近她在玩一个无双割草类的游戏,平面上有 \(n\) 个敌人,每一个敌人的坐标为 \(x_i,y_i\)。可怜有一个技能是在平面上画一个 \(m\) 个点的简单多边形,并消灭所有严格在多边形内部的敌人。

不难发现如果想要快速的消灭敌人的话,只要画一个足够大的简单多边形就行了。但是这样的游戏性就太差了。于是可怜打算为游戏增加一定的随机性。

可怜在平面上随便画了一个 \(m\) 个点的简单多边形 \((a_i,b_i)\)。接下来可怜打算按照 \([-\pi,\pi)\) 上的均匀分布随机选取数字 \(\alpha\)(可以理解为等概率选取),并把这个简单多边形绕原点逆时针旋转 \(\alpha\) 的角度(弧度制)。

现在可怜给你了每一个点的坐标,多边形的坐标,你的任务是帮助可怜计算在随机旋转后她期望可以消灭多少个敌人。

输入

第一行四个整数 \(n,m\)。

接下来 \(n\) 行每行两个整数 \(x_i,y_i\) 描述了一个敌人的坐标。

接下来 \(m\) 行每行两个整数 \(a_i,b_i\) 按照逆时针的顺序描述了简单多边形的每一个顶点。

输出

输出一行一个整数表示期望值,保留五位小数。同时保证所有数据的小数点后第 \(6\) 位在舍入前不会是 \(4\) 和 \(5\)。

输入示例

  1. 4 4
  2. 0 0
  3. 1 0
  4. -1 -1
  5. 0 1
  6. 0 0
  7. 1 0
  8. 1 1
  9. 0 1

输出示例

  1. 0.50000

数据规模及约定

对于 \(30\%\) 的数据,\(n,m \leq 15\)。

对于另外 \(30\%\) 的数据,选择的简单多边形是一个凸多边形。

对于 \(100\%\) 的数据,\(n \leq 200, m \leq 500, |x|,|y| \leq 10^6\).

题解

一道很裸的计算几何题,写一写练习一下,毕竟考场上这题爆零了很不爽……

考虑期望的线性性。我们可以对于每个敌人计算他被消灭的概率,将所有的概率累加即可。

多边形转可以变成固定多边形,然后转敌人的坐标。这样就变成了 \(n\) 次求圆有多少部分在多边形内部的问题。暴力求出圆与多边形的交点,然后对于每两个交点之间的弧,判一下这个弧的中点是否在多边形内部,如果在内部就将这个弧对应的圆心角 \(\theta\) 除以 \(2 \pi\) 的值累加即可。

需要的操作有:线段和圆求交点、线段和射线求交点(射线法)。

这个题需要调调 eps。eps 太小会 WA……

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. #define rep(i, s, t) for(int i = (s), mi = (t); i <= mi; i++)
  4. #define dwn(i, s, t) for(int i = (s), mi = (t); i >= mi; i--)
  5. int read() {
  6. int x = 0, f = 1; char c = getchar();
  7. while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
  8. while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
  9. return x * f;
  10. }
  11. #define maxn 510
  12. #define nxt(x) ((x + 1) % n)
  13. #define pre(x) ((x + n - 1) % n)
  14. const double eps = 1e-7, pi = acos(-1.0);
  15. int dcmp(double x) { return x < -eps ? -1 : (x > eps ? 1 : 0); }
  16. struct Vec {
  17. double x, y;
  18. Vec(double _ = 0, double __ = 0): x(_), y(__) {}
  19. Vec operator + (const Vec &t) const { return Vec(x + t.x, y + t.y); }
  20. Vec operator - (const Vec &t) const { return Vec(x - t.x, y - t.y); }
  21. Vec operator * (const double &t) const { return Vec(x * t, y * t); }
  22. Vec turnLeft() const { return Vec(-y, x); }
  23. Vec rotate(double a) { return Vec(cos(a) * x - sin(a) * y, cos(a) * y + sin(a) * x); }
  24. double operator * (const Vec &t) const { return x * t.x + y * t.y; }
  25. double operator ^ (const Vec &t) const { return x * t.y - y * t.x; }
  26. double len2() { return x * x + y * y; }
  27. double len() { return sqrt(len2()); }
  28. double ang() const { return atan2(y, x); }
  29. bool operator < (const Vec &t) const { return ang() < t.ang(); }
  30. } que[maxn], poly[maxn];
  31. int q, n;
  32. bool inPoly(Vec p) {
  33. bool ans = 0;
  34. rep(i, 0, n - 1) {
  35. Vec a = poly[i] - p, b = poly[nxt(i)] - p;
  36. if(dcmp(a.y) * dcmp(b.y) >= 0) continue;
  37. if(a.y > b.y) swap(a, b);
  38. if(dcmp(a ^ b) <= 0) continue;
  39. ans ^= 1;
  40. }
  41. return ans;
  42. }
  43. namespace SegCir {
  44. int tot;
  45. Vec crs[2];
  46. void intersect(double r, Vec p1, Vec p2) {
  47. Vec dir = (p1 - p2).turnLeft();
  48. double a = dir.x, b = dir.y, c = -a * p1.x - b * p1.y;
  49. double delta = 4.0 * b * b * (a * a * r * r - c * c + b * b * r * r);
  50. tot = 0;
  51. if(dcmp(delta) < 0) return ;
  52. if(delta < 0) delta = 0;
  53. double x, y;
  54. tot = 2;
  55. x = (-2.0 * a * c + sqrt(delta)) / (2.0 * (a * a + b * b));
  56. if(!dcmp(b)) y = sqrt(r * r - x * x); else y = (-a * x - c) / b;
  57. crs[0] = Vec(x, y);
  58. x = (-2.0 * a * c - sqrt(delta)) / (2.0 * (a * a + b * b));
  59. if(!dcmp(b)) y = -sqrt(r * r - x * x); else y = (-a * x - c) / b;
  60. crs[1] = Vec(x, y);
  61. if(!dcmp((crs[0] - crs[1]).len())) tot = 1;
  62. for(int i = 0; i < tot; i++)
  63. if(!dcmp((crs[i] - p2).len()) || dcmp((crs[i] - p1).len() + (crs[i] - p2).len() - (p1 - p2).len()))
  64. swap(crs[i], crs[tot-1]), i--, tot--;
  65. return ;
  66. }
  67. }
  68. Vec cs[maxn<<1];
  69. int cnt;
  70. double calc(double r) {
  71. if(!dcmp(r)) return inPoly(Vec(0, 0)) ? 1 : 0;
  72. cnt = 0;
  73. rep(i, 0, n - 1) {
  74. Vec a = poly[i], b = poly[nxt(i)];
  75. SegCir::intersect(r, a, b);
  76. rep(j, 0, SegCir::tot - 1) cs[cnt++] = SegCir::crs[j];
  77. }
  78. if(cnt <= 1) {
  79. double rang = pi / (rand() % 1000 + 1);
  80. Vec p(r * cos(rang), r * sin(rang));
  81. return inPoly(p) ? 1 : 0;
  82. }
  83. sort(cs, cs + cnt);
  84. double ans = 0;
  85. rep(i, 0, cnt - 1) {
  86. Vec a = cs[i], b = cs[(i+1)%cnt];
  87. double ang = a.ang(), bng = b.ang();
  88. if(bng < ang) bng += 2.0 * pi;
  89. double mng = (ang + bng) * .5;
  90. Vec mid(r * cos(mng), r * sin(mng));
  91. if(inPoly(mid)) ans += bng - ang;
  92. }
  93. return ans / (2.0 * pi);
  94. }
  95. int main() {
  96. srand((unsigned)time(NULL));
  97. int q = read(); n = read();
  98. double rang = pi / (rand() % 1000 + 1);
  99. rep(i, 1, q) {
  100. int x = read(), y = read();
  101. que[i] = Vec(x, y).rotate(rang);
  102. }
  103. rep(i, 0, n - 1) {
  104. int x = read(), y = read();
  105. poly[i] = Vec(x, y).rotate(rang);
  106. }
  107. double ans = 0;
  108. rep(i, 1, q) ans += calc(que[i].len());
  109. printf("%.5lf\n", ans);
  110. return 0;
  111. }

[LOJ#6437][BZOJ5373]「PKUSC2018」PKUSC的更多相关文章

  1. 【LOJ】#6437. 「PKUSC2018」PKUSC

    题解 我们把这个多边形三角形剖分了,和统计多边形面积一样 每个三角形有个点是原点,把原点所对应的角度算出来,记为theta 对于一个点,相当于半径为这个点到原点的一个圆,圆弧上的弧度为theta的一部 ...

  2. loj#6437. 「PKUSC2018」PKUSC(计算几何)

    题面 传送门 题解 计算几何的东西我好像都已经忘光了-- 首先我们可以把原问题转化为另一个等价的问题:对于每一个敌人,我们以原点为圆心,画一个经过该点的圆,把这个圆在多边形内部的圆弧的度数加入答案.求 ...

  3. LOJ#6437. 「PKUSC2018」PKUSC

    题面 题意转化为: 判断每个点所在的圆有多长的弧度角位于多边形内部. 然后就很暴力了. 每个点P,直接找到多边形和这个圆的所有交点,按照距离P的角度排序. 找交点,直接联立二元二次方程组.... 需要 ...

  4. 【LOJ】#6434. 「PKUSC2018」主斗地

    题解 什么,我这题竟然快到了LOJ rk1???? 搜起来有点麻烦,不过感觉还是比斗地主好下手(至今没敢写斗地主 首先是暴力搜牌型,最多\(3^{16}\)(什么判解还要复杂度怂成一团)的样子?? 然 ...

  5. LOJ6437. 「PKUSC2018」PKUSC [计算几何]

    LOJ 思路 显然多边形旋转可以变成点旋转,不同的点的贡献可以分开计算. 然后就变成了要求一个圆在多边形内的弧长. 考虑把交点全都求出来,那么两个交点之间的状态显然是相同的,可以直接把圆弧上的中点的状 ...

  6. 【LOJ】#6436. 「PKUSC2018」神仙的游戏

    题解 感觉智商为0啊QAQ 显然对于一个长度为\(len\)的border,每个点同余\(n - len\)的部分必然相等 那么我们求一个\(f[a]\)数组,如果存在\(s[x] = 0\)且\(s ...

  7. 【LOJ】#6435. 「PKUSC2018」星际穿越

    题解 想出70的大众分之后就弃疗了,正解有点神仙 就是首先有个比较显然的结论,就是要么是一直往左走,要么是走一步右边,然后一直往左走 根据这个可以结合RMQ写个70分的暴力 我们就考虑,最优的话显然是 ...

  8. 【LOJ】#6433. 「PKUSC2018」最大前缀和

    题解 神仙的状压啊QAQ 设一个\(f[S]\)表示数字的集合为\(S\)时\(sum[S]\)为前缀最大值的方案数 \(g[S]\)表示数字集合为\(S\)时所有前缀和都小于等于0的方案数 答案就是 ...

  9. 【LOJ】#6432. 「PKUSC2018」真实排名

    题解 简单分析一下,如果这个选手成绩是0,直接输出\(\binom{n}{k}\) 如果这个选手的成绩没有被翻倍,那么找到大于等于它的数(除了它自己)有a个,翻倍后不大于它的数有b个,那么就从这\(a ...

随机推荐

  1. Sencha Visual Studio(IDE插件)

    Sencha Visual Studio(IDE插件) 首先从官网上下载Visual Studio插件,注意不是VSCode编辑器,下载完后安装打开Visual Studio提示你去注册,输入你的se ...

  2. Laravel-admin 当使用Form组件hasMany的时候 进行编辑出现错误 foreach错误的时候解决方案

    我的关联关系原名是 goodImage 修改成 image 之后解决问题 分析得出应该是  laravel会将goodImage 转成 good_image字段  这样就foreach会报错  所以出 ...

  3. symfony 安装使用(一)

    Symfony安装教程网上已经存在很多了,但是这里还是要写一下: 1.symfony 安装有以下几种,对应不同的环境 1.1通过composer 命令安装 composer create-projec ...

  4. Hadoop(23)-Yarn资源调度器

    Yarn是一个资源调度平台,负责为运算程序提供服务器运算资源,相当于一个分布式的操作系统平台,而MapReduce等运算程序则相当于运行于操作系统之上的应用程序 1. Yarn工作机制 机制详解 第1 ...

  5. Go web表单

    package main import ( "fmt" "html/template" "log" "net/http" ...

  6. 【转】Git远程操作详解

    Git是目前最流行的版本管理系统,学会Git几乎成了开发者的必备技能. Git有很多优势,其中之一就是远程操作非常简便.本文详细介绍5个Git命令,它们的概念和用法,理解了这些内容,你就会完全掌握Gi ...

  7. 【PHP】进一法取整、四舍五入取整、忽略小数等的取整数方法大全

    PHP取整数函数常用的四种方法,下面收集了四个函数:经常用到取整的函数,今天小小的总结一下!其实很简单,就是几个函数而已--主要是:ceil,floor,round,intval PHP取整数函数常用 ...

  8. HMM相关文章索引

    HMM相关文章索引 1条回复 HMM系列文章是52nlp上访问量较高的一批文章,这里做个索引,方便大家参考. HMM学习 HMM学习最佳范例一:介绍 HMM学习最佳范例二:生成模式 HMM学习最佳范例 ...

  9. Java Swing 图形界面开发(目录)

    Java Swing 图形界面开发(目录) 2017年05月30日 23:50:42 阅读数:5228 本文链接: http://blog.csdn.net/xietansheng/article/d ...

  10. fiddler抓包工具的基本使用

    fiddler是基于C#的HTTP抓包工具. fiddler的原理: fiddler是http代理服务器,它会抓取浏览器向服务器发送的HTTP请求,然后在将该请求发送到服务器.再获取从服务器返回的请求 ...