【题解】折纸 origami [SCOI2007] [P4468] [Bzoj1074]
【题解】折纸 origami [SCOI2007] [P4468] [Bzoj1074]
传送门:折纸 \(\text{origami [SCOI2007] [P4468]}\) \(\text{[Bzoj1074]}\)
【题目描述】
初始有一个 \(100*100\) 的正方形纸片,现给出 \(n\) \((0 \leqslant n \leqslant 8)\) 条直线,将该纸片依次按照直线进行折叠,结束后会给出 \(m\) 个询问,每次询问求某个坐标上的点穿过了几层纸。
【分析】
又是一道毒瘤膜您题。
由于数据范围较小,可以直接上暴力。
考虑记录当前已有的多边形(初始为一个 \(100*100\) 的正方形),每折叠一次就把折叠线所穿过的所有多边形分成左右两部分,然后将右边部分的点全部关于折叠线对称,得到两个新的小多边形。
对于每次询问,暴力枚举统计 包含询问点的多边形 即可。
折叠 \(n\) 次后最多会出现 \(2^n\) 个多边形,每个多边形最多有 \(n^2\) 个点,射线法做一次 \(PIP\) 为 \(O(n^2)\),总时间复杂度为: \(O(m n^2 2^n)\) 。
注意:如果用的是 \(double\) 而不是 \(long\ double\),\(eps\) 开得过于小会导致答案出锅。
【Code】
#include<algorithm>
#include<cstdio>
#include<cmath>
#define LD double
#define LL long long
#define Re register int
#define Vector Point
using namespace std;
const int N=8;
const LD eps=1e-8;
inline int dcmp(LD a){return a<-eps?-1:(a>eps?1:0);}//处理精度
inline LD Abs(LD a){return a*dcmp(a);}//取绝对值
struct Point{
LD x,y;Point(LD X=0,LD Y=0){x=X,y=Y;}
inline void in(){scanf("%lf%lf",&x,&y);}
inline void out(){printf("%.2lf %.2lf\n",x,y);}
};
inline LD Dot(Vector a,Vector b){return a.x*b.x+a.y*b.y;}//【点积】
inline LD Cro(Vector a,Vector b){return a.x*b.y-a.y*b.x;}//【叉积】
inline LD Len(Vector a){return sqrt(Dot(a,a));}//【模长】
inline LD Angle(Vector a,Vector b){return acos(Dot(a,b)/Len(a)/Len(b));}//【两向量夹角】
inline Vector operator+(Vector a,Vector b){return Vector(a.x+b.x,a.y+b.y);}
inline Vector operator-(Vector a,Vector b){return Vector(a.x-b.x,a.y-b.y);}
inline Vector operator*(Vector a,LD b){return Vector(a.x*b,a.y*b);}
inline bool operator==(Point a,Point b){return !dcmp(a.x-b.x)&&!dcmp(a.y-b.y);}//两点坐标重合则相等
inline int pan_PL(Point p,Point a,Point b){//【判断点P是否在线段AB上】
return !dcmp(Cro(p-a,b-a))&&dcmp(min(a.x,b.x)-p.x)<=0&&dcmp(p.x-max(a.x,b.x))<=0&&dcmp(min(a.y,b.y)-p.y)<=0&&dcmp(p.y-max(a.y,b.y))<=0;
//PA,AB共线且P在AB之间
}
inline int pan_PL_(Point p,Point a,Point b){//【判断点P是否在直线AB上】
return !dcmp(Cro(p-a,b-a));//PA,AB共线
}
inline Point FootPoint(Point p,Point a,Point b){//【点P到直线AB的垂足】
Vector x=p-a,y=p-b,z=b-a;
LD len1=Dot(x,z)/Len(z),len2=-1.0*Dot(y,z)/Len(z);//分别计算AP,BP在AB,BA上的投影
return a+z*(len1/(len1+len2));//点A加上向量AF
}
inline Point Symmetry_PL(Point p,Point a,Point b){//【点P关于直线AB的对称点】
return p+(FootPoint(p,a,b)-p)*2;//将PF延长一倍即可
}
inline Point cross_LL(Point a,Point b,Point c,Point d){//【两直线AB,CD的交点】
Vector x=b-a,y=d-c,z=a-c;
return a+x*(Cro(y,z)/Cro(x,y));//点A加上向量AF
}
inline int pan_cross_L_L(Point a,Point b,Point c,Point d){//【判断直线AB与线段CD是否相交】
return pan_PL(cross_LL(a,b,c,d),c,d);//直线AB与直线CD的交点在线段CD上
}
inline int PIP(Point *P,Re n,Point a){//【射线法】判断点A是否在任意多边形Poly以内
Re cnt=0;LD tmp;
for(Re i=1;i<=n;++i){
Re j=i<n?i+1:1;
if(pan_PL(a,P[i],P[j]))return 2;//点在多边形上
if(a.y>=min(P[i].y,P[j].y)&&a.y<max(P[i].y,P[j].y))//纵坐标在该线段两端点之间
tmp=P[i].x+(a.y-P[i].y)/(P[j].y-P[i].y)*(P[j].x-P[i].x),cnt+=dcmp(tmp-a.x)>0;//交点在A右方
}
return cnt&1;//穿过奇数次则在多边形以内
}
inline int judge(Point a,Point L,Point R){//判断AL是否在AR右边
return dcmp(Cro(L-a,R-a))>0;
}
struct Poly{int n;Point P[N*N+3];}Py[(1<<N)+3],Qy[(1<<N)+3];
int n,t,tt,T;Point a,b;
inline void sakura(Poly Po,Point a,Point b){
Poly L,R;L.n=R.n=0;
for(Re i=1;i<=Po.n;++i){
if(judge(a,Po.P[i],b))R.P[++R.n]=Symmetry_PL(Po.P[i],a,b);//点Po.P[i]在直线ab右边
else if(pan_PL_(Po.P[i],a,b))L.P[++L.n]=R.P[++R.n]=Po.P[i];//点Po.P[i]在直线ab上
else L.P[++L.n]=Po.P[i];//点Po.P[i]在直线ab左边
Re j=i<Po.n?i+1:1;
if(pan_cross_L_L(a,b,Po.P[i],Po.P[j]))L.P[++L.n]=R.P[++R.n]=cross_LL(a,b,Po.P[i],Po.P[j]);//如果直线AB与线段P[i]-P[i+1]有交点,将这个交点入队
while(L.n>1&&L.P[L.n]==L.P[L.n-1])--L.n;//可能会重复如归,这里迅速把它去掉
while(R.n>1&&R.P[R.n]==R.P[R.n-1])--R.n;//同上
}
if(L.n>1&&L.P[1]==L.P[L.n])--L.n;//注意最后判断首尾两点是否重合
if(R.n>1&&R.P[1]==R.P[R.n])--R.n;//同上
if(L.n)Qy[++tt]=L;//如果小矩形不为空就记录下来
if(R.n)Qy[++tt]=R;
}
int main(){
// freopen("123.txt","r",stdin);
scanf("%d",&n);
Py[++t].n=4,Py[t].P[1]=Point(0,0),Py[t].P[2]=Point(0,100),Py[t].P[3]=Point(100,100),Py[t].P[4]=Point(100,0);
//初始化为一个正方形
while(n--){
a.in(),b.in(),tt=0;
for(Re i=1;i<=t;++i)sakura(Py[i],a,b);//切割目前已有的多边形
t=tt;
for(Re i=1;i<=tt;++i)Py[i]=Qy[i];
}
scanf("%d",&T);
while(T--){
a.in();Re ans=0;
for(Re i=1;i<=t;++i)if(PIP(Py[i].P,Py[i].n,a)==1)++ans;//严格在多边形内才统计答案
printf("%d\n",ans);
}
}
【题解】折纸 origami [SCOI2007] [P4468] [Bzoj1074]的更多相关文章
- 【BZOJ】1074: [SCOI2007]折纸origami
http://www.lydsy.com/JudgeOnline/problem.php?id=1074 题意:一开始有一个左上角是(0,100),右下角是(100,0)的纸片,现在可以沿有向直线折n ...
- 1074: [SCOI2007]折纸origami - BZOJ
Description 桌上有一张边界平行于坐标轴的正方形纸片,左下角的坐标为(0,0),右上角的坐标为(100,100).接下来执行n条折纸命令.每条命令用两个不同点P1(x1,y1)和P2(x2, ...
- 1074: [SCOI2007]折纸origami
Time Limit: 20 Sec Memory Limit: 162 MBSubmit: 372 Solved: 229[Submit][Status][Discuss] Descriptio ...
- BZOJ1074 [SCOI2007]折纸origami
我们先看每个点可能从哪些点折过来的,2^10枚举对角线是否用到. 然后再模拟折法,查看每个点是否满足要求. 恩,计算几何比较恶心,还好前几天刚写过一道更恶心的计算几何,点类直接拷过来2333. /** ...
- [CSP-S模拟测试]:折纸(模拟)
题目描述 小$s$很喜欢折纸.有一天,他得到了一条很长的纸带,他把它从左向右均匀划分为$N$个单位长度,并且在每份的边界处分别标上数字$0\sim n$.然后小$s$开始无聊的折纸,每次他都会选择一个 ...
- NOIP模拟测试21「折纸·不等式」
折纸 题解 考试时无限接近正解,然而最终也只是接近而已了 考虑模拟会爆炸,拿手折纸条试一试,很简单 考你动手能力 代码 #include<bits/stdc++.h> using name ...
- CSS3写折纸
<!DOCTYPE HTML> <html> <head> <meta http-equiv="Content-Type" content ...
- 折纸问题java实现
/** * 折纸问题 这段代码写的太low了 本人水平有限 哎... 全是字符串了 * @param n * @return * @date 2016-10-7 * @author shaobn */ ...
- CSS3实现文字折纸效果
CSS3实现文字折纸效果 效果图: 代码如下,复制即可使用: <!DOCTYPE html> <html> <head> <title></tit ...
随机推荐
- gdb调试入门(下)
GDB调试主要包括: 1.查看运行时数据 2.程序错误 3.gdb调试逻辑错误 4.gdb调试段错误 5.core文件调试 一.查看运行时数据 1.print 查看变量值 2.ptype 变量: 查看 ...
- TCP/IP协议图解
联网的各个终端之间能否进行交互的软件基础是网络协议栈,目前主流的网络协议栈是TCP/IP协议栈. 1.主机到网络层协议:以太网协议 主机到网络层主要为IP协议和ARP协议提供服务.发送和接收网络数据报 ...
- rbd的删除回收站功能
前言 rbd 提供了一个回收站功能,这个是属于防呆设计,防止误操作删除rbd引起无法恢复的情况,rbd正常情况下的删除是马上会在后台回收空间的,这个也听说过有人做过误删除的操作,那么这个设计就是从操作 ...
- 面试常问的 25+ 个 Linux 命令
作为一个Java开发人员,有些常用的Linux命令必须掌握.即时平时开发过程中不使用Linux(Unix)或者mac系统,也需要熟练掌握Linux命令.因为很多服务器上都是Linux系统.所以,要和服 ...
- To the Max(动态规划)
Description Given a two-dimensional array of positive and negative integers, a sub-rectangle is any ...
- LeetCode-Python-删除链表解题思路
给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点. image.png 解题思路: 使用双指针,快指针与慢指针的间隔为n: 涉及到最后要删除慢指针的节点,为了方便,先开辟一个nod ...
- C# 中的本地函数
今天我们来聊一聊 C# 中的本地函数.本地函数是从 C# 7.0 开始引入,并在 C# 8.0 和 C# 9.0 中加以完善的. 引入本地函数的原因 我们来看一下微软 C# 语言首席设计师 Mads ...
- Mac升级资料丢失怎么办?EasyRecovery能恢复嘛?
随着越来越多的用户选择性能更高的mac笔记本来工作,一般情况下,为了保证用户有一个很好的使用体验,Mac系统会在一定的时间内进行系统的更新,弥补前一个版本的不足.结果就有一些用户反应Mac升级后,电脑 ...
- ntfs和fat32的区别
ntfs和fat32是两种不同的磁盘文件系统格式,虽然他们有一定的相似点,但还是具有很大的差异.今天,小编就带大家了解一下ntfs和fat32的区别. 图1 :u盘 一.分区容量 fat32能够有效管 ...
- linkedin第三方登陆
到linkedin注册成为开发者:https://developer.linkedin.com/zh-cn 成功后,创建应用,填写重定向地址,得到appid和appkey 使用这个sdk https: ...