我们有相遇的时间(time)

发布时间 2023-08-04 22:48:07作者: _kkio

终于还是写到这个了。。。

题意:

一个平面直角坐标系上,给你六个点,分别是 \((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\) 轴上一点。一个很好的想法是这样:

1

上下两条线的情况本质是对称的,只需要得到两条线上的任意一点即可。

考虑倍增。每次将长度乘二或乘二加一。

实现方式是找到四个点 \((0,\frac{1}{3}),(\frac{1}{3},\frac{1}{3}),(1,\frac{4}{3}),(\frac{4}{3},\frac{4}{3})\),发现如果以 \((0,0)\)\((1,1)\) 为基准点,当点在 \(y=1\) 上时,\(d\) 为它到 \((1,1)\) 距离,当在 \(y=0\) 上时为到 \((0,0)\) 的距离,那么以 \((0,0)\) 为起始点,\(d\) 初始为 \(0\)。若是当前点和 \((0,\frac{2}{3})\)\((1,\frac{4}{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;
}