1074: [SCOI2007]折纸origami

Description

桌上有一张边界平行于坐标轴的正方形纸片,左下角的坐标为(0,0),右上角的坐标为(100,100)。接下来执行n条折纸命令。每条命令用两个不同点P1(x1,y1)和P2(x2,y2)来表示,执行时把当前的折纸作品沿着P1P2所在直线折叠,并把有向线段P1P2的右边折向左边(左边的部分保持不变)。折叠结束后,需要在作品上打一个孔,然后用绳子穿起来挂在墙上。孔的位置是相当重要的:若需要穿过太多层的纸,打孔本身比较困难;若穿过的层数太少,悬挂起来以后作品可能会被撕破。为了选择一个比较合适的打孔位置,你需要计算在每个候选位置打孔时穿过的层数。如果恰好穿过某一层的边界(误差0.000001内),则该层不统计在结果中。本题考虑一个简化的模型:纸的厚度不计,因此折纸操作总能完美执行。
Input

输入第一行为一个整数n,即折纸的次数。以下n行每行四个实数x1,y1,x2,y2,表示每次折纸时对应的有向线段。下一行包含一个正整数m,即候选位置的个数,以下每行包含两个实数x,y,表示一个候选位置。
Output

每个候选位置输出一行,包含一个整数,即该位置打孔时穿过的层数。
Sample Input
2
-0.5 -0.5 1 1
1 75 0 75
6
10 60
80 60
30 40
10 10
50 50
20 50

Sample Output
4
2
2
0
0
2


HINT

样例说明 【限制】 20%的数据满足:n<=1 100%的数据满足:0<=n<=8, 1<=m<=50

话说我也不知道我怎么就想到了这个想法

对于每个询问,我们可以暴力求出它穿过的点原来是在什么位置,因为n<=8,所以最多有2^8个点,然后排序判重(话说我排序只是为了好判重)

再对每一个点做一遍那n个操作,看是不是落在现在这个点,是的话ans+1

然后就做完了

求对称点的话,我是用向量求的,用向量可以很容易计算出距离,然后求直线的法向量,就是直接旋转90度,再用那个点加上法向量的多少倍(用距离算一下)就是对称点了

思路倒是清晰,只是判重的时候傻×了一下,我本来是想排序后相同的就把前面的改掉,写着写着就变成把后边的改掉,答案就大了好多

  1 const
  2     eps=1e-6;
  3 type
  4     segment=record
  5       x1,y1,x2,y2:double;
  6     end;
  7     point=record
  8       x,y:double;
  9     end;
 10 var
 11     n,m:longint;
 12     a:array[0..8]of segment;
 13     b:array[0..300]of point;
 14 
 15 function cj(x1,y1,x2,y2:double):double;
 16 begin
 17     exit(x1*y2-y1*x2);
 18 end;
 19 
 20 procedure init;
 21 var
 22     i:longint;
 23 begin
 24     read(n);
 25     for i:=1 to n do
 26       with a[i] do
 27         read(x1,y1,x2,y2);
 28 end;
 29 
 30 procedure swap(var x,y:point);
 31 var
 32     t:point;
 33 begin
 34     t:=x;x:=y;y:=t;
 35 end;
 36 
 37 procedure sort(l,r:longint);
 38 var
 39     i,j:longint;
 40     y:point;
 41 begin
 42     i:=l;
 43     j:=r;
 44     y:=b[(l+r)>>1];
 45     repeat
 46       while (b[i].x<y.x) or ((b[i].x=y.x)and(b[i].y<y.y)) do
 47         inc(i);
 48       while (b[j].x>y.x) or ((b[j].x=y.x)and(b[j].y>y.y)) do
 49         dec(j);
 50       if i<=j then
 51       begin
 52         swap(b[i],b[j]);
 53         inc(i);
 54         dec(j);
 55       end;
 56     until i>j;
 57     if i<r then sort(i,r);
 58     if j>l then sort(l,j);
 59 end;
 60 
 61 procedure get(b:point;c:segment;var a:point);
 62 var
 63     d:double;
 64 begin
 65     a.x:=c.y1-c.y2;
 66     a.y:=c.x2-c.x1;
 67     d:=cj(c.x2-c.x1,c.y2-c.y1,b.x-c.x1,b.y-c.y1)/sqrt(sqr(c.x1-c.x2)+sqr(c.y1-c.y2));
 68     a.x:=a.x/sqrt(sqr(c.x1-c.x2)+sqr(c.y1-c.y2));
 69     a.y:=a.y/sqrt(sqr(c.x1-c.x2)+sqr(c.y1-c.y2));
 70     a.x:=b.x-a.x*d*2;
 71     a.y:=b.y-a.y*d*2;
 72 end;
 73 
 74 procedure work;
 75 var
 76     i,j,k,num,ans:longint;
 77 begin
 78     read(m);
 79     for i:=1 to m do
 80       begin
 81         ans:=0;
 82         with b[1] do
 83           read(x,y);
 84         b[0]:=b[1];
 85         num:=1;
 86         for j:=n downto 1 do
 87           begin
 88             for k:=1 to num do
 89               get(b[k],a[j],b[k+num]);
 90             num:=num<<1;
 91           end;
 92         sort(1,num);
 93         for j:=2 to num do
 94           if (abs(b[j].x-b[j-1].x)<eps) and (abs(b[j-1].y-b[j].y)<eps) then b[j-1].x:=100000;
 95         for j:=1 to num do
 96           if not((b[j].x>eps) and (b[j].x+eps<100) and (b[j].y>eps) and (b[j].y+eps<100)) then b[j].x:=1000
 97           else
 98           for k:=1 to n do
 99             if abs(cj(a[k].x2-a[k].x1,a[k].y2-a[k].y1,b[j].x-a[k].x1,b[j].y-a[k].y1))<eps then b[j].x:=1000000
100             else
101             if cj(a[k].x2-a[k].x1,a[k].y2-a[k].y1,b[j].x-a[k].x1,b[j].y-a[k].y1)<0 then get(b[j],a[k],b[j]);
102         for j:=1 to num do
103           if (abs(b[j].x-b[0].x)<eps) and (abs(b[j].y-b[0].y)<eps) then inc(ans);
104         writeln(ans);
105       end;
106 end;
107 
108 begin
109     init;
110     work;
111 end.
View Code
原文地址:https://www.cnblogs.com/Randolph87/p/3629347.html