1074: [SCOI2007]折纸origami - BZOJ

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
1074: [SCOI2007]折纸origami - BZOJ
样例说明 【限制】 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

 

你可能感兴趣的:(2007)