终于还是写到这个了。。。
题意:
一个平面直角坐标系上,给你六个点,分别是 \((0,0),(0,1),(1,0),(1,1),(0,0.5),(1,0.5)\)。你随时可以做两种操作,第一种是选两个点的编号,在这两个点之间得到一条直线,这条直线的编号为上个直线编号加一,第二种选两条有交直线,并得到交点,交点编号为上个点编号加一。
现在给你四个参数 \(0<Xa<Xb<1e9,0<Ya<Yb<1e9\),构造一种操作方案得到点 \((\frac{Xa}{Xb},\frac{Ya}{Yb})\)。使操作一总次数不超过 \(270\) 次。
解法
考虑如何得到坐标轴上的任意一点,再做过这个点的平行坐标的线,求交就好了。\(X\) 轴 \(Y\) 轴本质一样,现在考虑 \(Y\) 轴上一点。一个很好的想法是这样:
上下两条线的情况本质是对称的,只需要得到两条线上的任意一点即可。
考虑倍增。每次将长度乘二或乘二加一。
实现方式是找到四个点 \((0,\frac{1}{3}),(\frac{1}{3},\frac{1}{3}),(1,\frac{5}{3}),(\frac{5}{3},\frac{5}{3})\),发现如果以 \((0,0)\) 和 \((1,1)\) 为基准点,当点在 \(y=1\) 上时,\(d\) 为它到 \((1,1)\) 距离,当在 \(y=0\) 上时为到 \((0,0)\) 的距离,那么以 \((0,0)\) 为起始点,\(d\) 初始为 \(0\)。若是当前点和 \((0,\frac{1}{3})\) 或 \((1,\frac{5}{3})\) 作直线交 \(y=0\) 或 \(y=1\) 于另一个点时,这个点的 \(d\) 会乘二并加一,如果是另外两个点的话就只会乘二。
如图,点 \(B\) 的 \(d\) 为 \(1\),连出两条直线于 \(y=1\) 交点的 \(d\) 分别是 \(3\) 和 \(2\)。
以此就可以倍增了。剩下的两件事,一是得到那四个点,而是作一条过任意点并平行于坐标轴的直线,这是初中直尺作图简单的,应该有一万种做法。
#include <bits/stdc++.h>
using namespace std;
int pid,lid;
struct opt{int type,a,b;};
vector<opt> Ans;
inline int getl(int A,int B)
{Ans.push_back({1,A,B});++lid;return lid;}
inline int getp(int la,int lb)
{Ans.push_back({0,la,lb});++pid;return pid;}
struct solver{
int A,B,C,D,M1,M2,I,E,F,G,H;
int lf,lg;
inline void beready()
{
lf=getl(A,B);lg=getl(C,D);
int tl=getl(C,A),tr=getl(D,B);
int tp=getl(B,M1),tq=getl(D,M2);
F=getp(tl,tp),H=getp(tl,tq);
tl=getl(C,M1),tr=getl(A,M2);
int tmp1=getp(lf,tl),tmp2=getp(lg,tr);
int cr=getl(tmp1,tmp2);
E=getp(cr,getl(A,D)),G=getp(cr,getl(C,B));
}
int calc(int X,int opt)
{
int d=0;
int nwp=((opt==0)?A:C);
for(int i=30;i>=0;i--)
{
if(X&(1<<i))
{
if(((i&1)^opt)==0){nwp=getp(getl(nwp,E),lg);}
else {nwp=getp(getl(nwp,G),lf);}
d=d<<1|1;
}
else
{
if(((i&1)^opt)==0){nwp=getp(getl(nwp,F),lg);}
else {nwp=getp(getl(nwp,H),lf);}
d=d<<1;
}
}
return nwp;
}
inline int getP(int Ya,int Yb)
{
if(Ya==1&&Yb==2)return getl(M1,M2);
int upP=calc(Yb-Ya+1,0);
int dwP=calc(Ya,1);
int RP=getp(getl(upP,dwP),getl(A,D));
int RG=getp(getl(RP,I),getl(C,B));
int tk=getp(lg,getl(A,M2));int tl=getp(lf,getl(D,M2));
int EI=getp(getl(tk,B),getl(tl,C));
return getl(RP,getp(getl(tk,tl),getl(RG,EI)));
}
}SX,SY;
int Xa,Xb,Ya,Yb;
int A,B,C,D,M1,M2,M3,M4,I,ans=1;
int main()
{
// freopen("ex_time1.in","r",stdin);
// freopen("time.out","w",stdout);
scanf("%d%d%d%d",&Xa,&Xb,&Ya,&Yb);
int g1=__gcd(Xa,Xb),g2=__gcd(Ya,Yb);
Xa/=g1,Xb/=g1,Ya/=g2,Yb/=g2;
pid=6;A=1,M1=2,D=3,B=4,M2=5,C=6;
I=getp(getl(A,C),getl(B,D));
M3=getp(getl(C,D),getl(getp(getl(getp(getl(C,M1),getl(B,A)),D),getl(B,C)),A));
M4=getp(getl(M3,I),getl(A,B));
SX.A=A,SX.B=B,SX.C=C,SX.D=D,SX.M1=M1,SX.M2=M2,SX.I=I;
SY.A=A,SY.B=D,SY.C=C,SY.D=B,SY.M1=M4,SY.M2=M3,SY.I=I;
SX.beready();SY.beready();
int TY=SX.getP(Ya,Yb);
int TX=SY.getP(Xa,Xb);
ans=getp(TX,TY);
printf("%d\n",Ans.size()+1);
for(auto v:Ans)printf("%d %d %d\n",v.type,v.a,v.b);
printf("2 %d\n",ans);
return 0;
}
标签:直线,getl,int,相遇,tl,时间,time,getp,frac
From: https://www.cnblogs.com/hikkio/p/17607255.html