【题解】折纸 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 ...
随机推荐
- Failed connect to mirrors.cloud.aliyuncs.com:80
在yum insatall 安装是报错 Failed connect to mirrors.cloud.aliyuncs.com:80; Connection refused 解决方法: cd /et ...
- APP分享多张图片到微信和朋友圈
产品需求: 微信分享多图至好友,朋友圈.由于微信禁用了分享9图至朋友圈功能,这里分享微信只是将图片保存至本地,具体让用户手动分享. 问题分析: 微信没有提供分享多图的SDK,因此我们实现调用系统自带的 ...
- JS之DOM(一)
一.DOM简介 什么是DOM?简单地说,DOM是是针对HTML和XML文档的一个API,一套对文档的内容进行抽象和概念化的方法. 学习过ORM的同学可能知道ORM是将数据库中的表映射到类,建立一个表和 ...
- Java从后端下载文件到浏览器
// 注: // 获取项目下文件或者文件流 // File file = new File(this.getClass().getResource("/xls/adminImportUser ...
- 厉害啊!第一次见到把Shiro运行流程写的这么清楚的,建议收藏起来慢慢看
前言 shiro是apache的一个开源框架,是一个权限管理的框架,实现 用户认证.用户授权. spring中有spring security (原名Acegi),是一个权限框架,它和spring依赖 ...
- 通过RayFire为图形添加二次破碎效果
在完成3D建模之后,RayFire能帮助用户制作多种类型的破碎效果,如均匀碎片.放射状碎片.木碎等效果.另外,用户还可以利用RayFire的碎片选取功能,为图形进行二次破碎,以达到增加局部碎片的效果. ...
- CorelDRAW:油漆滚轮及LOGO设计
小马坐在电脑前,看着自己画的油漆滚轮Logo,既生气又无奈.为了这个油漆Logo,小马用了四.五个不同的设计软件,也画了不下10个图案,就没有一个满意的."明天就要交稿了,现在都11点多了, ...
- mysql三种删除方式
一般来说mysql有三种删除数据方式: 1. delete(常用) 2. truncate(慎用) 3. drop 以上三种方式都可以删除数据,但是使用场景是不同的. 从执行速度来说: drop &g ...
- python 如何跳过异常继续执行
使用try...except...语句,类似于if...else...,可以跳过异常继续执行程序,这是Python的优势 用法如下: 1 2 3 4 5 6 try: # 可能会 ...
- Java 滴IO系统
JAVA IO 流可以概括为 "两个对应,一个桥梁".两个对应指字节流(Byte Stream)和字符流(Char Stream)的对应,输入流和输出流的对应. 一个桥梁指从字节流 ...