【LOJ】#2039. 「SHOI2015」激光发生器
题解
我永远都写不对计算几何……
首先找到反射的线段比较好找,扫一遍所有线段然后找交点在镜子上并且交点离起点最近的那条线段
然后旋转的时候,有可能是顺时针,也有可能是逆时针,要找出法线,然后判断法线和光线的角度然后确定顺时针逆时针
代码
#include <bits/stdc++.h>
#define enter putchar('\n')
#define space putchar(' ')
#define pii pair<int,int>
#define fi first
#define se second
#define MAXN 200005
#define pb push_back
#define eps 1e-8
//#define ivorysi
using namespace std;
typedef long long int64;
typedef double db;
template<class T>
void read(T &res) {
res = 0;T f = 1;char c = getchar();
while(c < '0' || c > '9') {
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9') {
res = res * 10 + c - '0';
c = getchar();
}
res *= f;
}
template<class T>
void out(T x) {
if(x < 0) {x = -x;putchar('-');}
if(x >= 10) out(x / 10);
putchar('0' + x % 10);
}
bool dcmp(db a,db b) {
return fabs(a - b) < eps;
}
struct Point {
db x,y;
Point(){}
Point(db _x,db _y) {
x = _x;y = _y;
}
friend Point operator + (const Point &a,const Point &b) {
return Point(a.x + b.x,a.y + b.y);
}
friend Point operator - (const Point &a,const Point &b) {
return Point(a.x - b.x,a.y - b.y);
}
friend Point operator * (const Point &a,const db &d) {
return Point(a.x * d,a.y * d);
}
friend Point operator / (const Point &a,const db &d) {
return Point(a.x / d,a.y / d);
}
friend db operator * (const Point &a,const Point &b) {
return a.x * b.y - a.y * b.x;
}
friend db dot(const Point &a,const Point &b) {
return a.x * b.x + a.y * b.y;
}
db norm() {
return sqrt(x * x + y * y);
}
};
struct Seg {
Point a,b;db theta;
Seg(){}
Seg(Point _a,Point _b,db _theta = 0.0) {
a = _a;b = _b;theta = _theta;
}
friend Point Cross_Point(const Seg &s,const Seg &t) {
db S1 = (s.a - t.a) * (t.b - t.a);
db S2 = (s.b - t.b) * (t.a - t.b);
return s.a + (s.b - s.a) * (S1 / (S1 + S2));
}
bool in_Seg(Point P) {
db d = (a - P) * (b - P);
if(!dcmp(d,0.0)) return false;
return dot((a - P),(b - P)) <= eps;
}
}S[105],L;
const db PI = acos(-1.0);
int N,ans[15],tot;
void Init() {
db sx,sy,tx,ty,theta,a,b;
scanf("%lf%lf%lf%lf",&sx,&sy,&tx,&ty);
L = Seg(Point(sx,sy),Point(sx + tx,sy + ty));
read(N);
for(int i = 1 ; i <= N ; ++i) {
scanf("%lf%lf%lf%lf%lf%lf",&sx,&sy,&tx,&ty,&a,&b);
theta = a / b;
S[i] = Seg(Point(sx,sy),Point(tx,ty),theta);
}
}
void Solve() {
int cnt = 10;
while(cnt--) {
int id = -1;Point t;
for(int i = 1 ; i <= N ; ++i) {
if(i == ans[tot]) continue;
Point p = Cross_Point(L,S[i]);
if(S[i].in_Seg(p) && dot(L.b - L.a,p - L.a) >= -eps) {
if(id == -1) {id = i;t = p;}
else if((p - L.a).norm() < (t - L.a).norm()) {
id = i;t = p;
}
}
}
if(id == -1) break;
ans[++tot] = id;
db d = dot(L.b - L.a,S[id].b - S[id].a);
db alpha = acos(fabs(d) / ((L.b - L.a).norm() * (S[id].b - S[id].a).norm()));
alpha = PI / 2 - alpha;
alpha = (S[id].theta + 1) * alpha;
L.b = L.a;L.a = t;
Seg ver = Seg(t,t + Point(-(S[id].b - S[id].a).y,(S[id].b - S[id].a).x));
if(dot(ver.b - ver.a,L.b - L.a) <= eps) {
ver = Seg(t,t + Point((S[id].b - S[id].a).y,-(S[id].b - S[id].a).x));
}
Point tmp = L.b - t;
if((ver.b - ver.a) * (L.b - L.a) >= -eps) alpha = -alpha;
L.b = t + Point(tmp.x * cos(alpha) - tmp.y * sin(alpha),tmp.x * sin(alpha) + tmp.y * cos(alpha));
}
if(!tot) puts("NONE");
else {
for(int i = 1 ; i <= tot ; ++i) {
out(ans[i]);space;
}
enter;
}
}
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
Init();
Solve();
return 0;
}
【LOJ】#2039. 「SHOI2015」激光发生器的更多相关文章
- [LOJ 2039] 「SHOI2015」激光发生器
[LOJ 2039] 「SHOI2015」激光发生器 链接 链接 题解 分为两个部分 第一个是求直线之间的交点找到第一个触碰到的镜面 第二个是求直线经过镜面反射之后的出射光线 第一个很好做,第二个就是 ...
- LOJ#2039. 「SHOI2015」激光发生器(计算几何)
题面 传送门 题解 如果我初中科学老师知道我有一天计算的时候入射角不等于反射角不知道会不会把我抓起来打一顿-- 这题本质上就是个模拟,需要的芝士也就计蒜几盒的那点,不过注意细节很多,放到考场上只能看看 ...
- loj#2038. 「SHOI2015」超能粒子炮・改
题目链接 loj#2038. 「SHOI2015」超能粒子炮・改 题解 卢卡斯定理 之后对于%p分类 剩下的是个子问题递归 n,k小于p的S可以预处理,C可以卢卡斯算 代码 #include<c ...
- loj #2037. 「SHOI2015」脑洞治疗仪
#2037. 「SHOI2015」脑洞治疗仪 题目描述 曾经发明了自动刷题机的发明家 SHTSC 又公开了他的新发明:脑洞治疗仪——一种可以治疗他因为发明而日益增大的脑洞的神秘装置. 为了简单起见 ...
- Loj #2036. 「SHOI2015」自动刷题机
link : https://loj.ac/problem/2036 这个显然具有单调性,N小的话更容易A题,不仅因为A一次题减少的代码,并且A题的下限也低. 所以直接上二分就行了,注意上限一定不要设 ...
- Loj #2192. 「SHOI2014」概率充电器
Loj #2192. 「SHOI2014」概率充电器 题目描述 著名的电子产品品牌 SHOI 刚刚发布了引领世界潮流的下一代电子产品--概率充电器: 「采用全新纳米级加工技术,实现元件与导线能否通电完 ...
- Loj #3096. 「SNOI2019」数论
Loj #3096. 「SNOI2019」数论 题目描述 给出正整数 \(P, Q, T\),大小为 \(n\) 的整数集 \(A\) 和大小为 \(m\) 的整数集 \(B\),请你求出: \[ \ ...
- Loj #3093. 「BJOI2019」光线
Loj #3093. 「BJOI2019」光线 题目描述 当一束光打到一层玻璃上时,有一定比例的光会穿过这层玻璃,一定比例的光会被反射回去,剩下的光被玻璃吸收. 设对于任意 \(x\),有 \(x\t ...
- Loj #3089. 「BJOI2019」奥术神杖
Loj #3089. 「BJOI2019」奥术神杖 题目描述 Bezorath 大陆抵抗地灾军团入侵的战争进入了僵持的阶段,世世代代生活在 Bezorath 这片大陆的精灵们开始寻找远古时代诸神遗留的 ...
随机推荐
- Nginx跳转Tomcat
conf配置: server { listen 80; server_name www.-------.com; server_name_i ...
- 出了一个js的题。
class test { set xx(v){ console.log('i am set'); this.__ok = v; } get xx(){ console.log('i am get'); ...
- Spark MLlib使用有感
这些天在公司里面做文本分析的任务,我跟着玻哥一起做,先研究了算法的可行度,最后决定使用Google的Word2Vector和LDA算法来对文本进行分析.之前因为看过一些Spark的东西,所以准备瞄准M ...
- oracle05
1. 数据处理 说完了所有的查询,下面说说增.删.改. 1.1. Update 在plsql Developer工具中,加上rowid可以更改数据. 使用工具进行更新数据的操作 在工具中更新数据方式一 ...
- std 与标准库
1.命名空间std C++标准中引入命名空间的概念,是为了解决不同模块或者函数库中相同标识符冲突的问题.有了命名空间的概念,标识符就被限制在特定的范围(函数)内,不会引起命名冲突.最典型的例子就是st ...
- Linux路径名和文件名最大长度限制
UNIX标准对路径名和文件名最大长度限制做出了说明,但其上限值在实际应用长过小,Linux在具体实现时提升了该上限,该限制在Linux的 /usr/include/linux/limits.h 中做出 ...
- Android平台介绍
一.Android平台介绍 什么是智能手机 具有独立的操作系统,独立的运行空间,可以由用户自行安装软件.游戏.导航等第三方应用程序,并可以通过移动通讯网络来实现无线网络接入的手机类型总称. 智能手机操 ...
- Linux信息搜集
## 1.取证工具 - LiME 内存获取工具 - volatility 内存分析工具 ## 2.机器信息收集 #sysinfo 16 # # 查看当前登录用户 who > who.txt # ...
- Framebuffer 驱动学习总结(二)---- Framebuffer模块初始化
---恢复内容开始--- Framebuffer模块初始化过程:--driver\video\fbmem.c 1. 初始化Framebuffer: FrameBuffer驱动是以模块的形式注册到系统 ...
- kworker内核工作队列详解
工作队列是另一种将工作推后执行的形式,它可以把工作交给一个内核线程去执行,这个下半部是在进程上下文中执行的,因此,它可以重新调度还有睡眠. 区分使用软中断/tasklet还是工作队列比较简单,如 ...