editorial

Правка en3, от installb, 2025-09-08 20:47:06

2139A — Maple and Multiplication

2139B — Cake Collection

2138A — Cake Assignment

2138B — Antiamuny Wants to Learn Swap

2138C1 — Maple and Tree Beauty (Easy Version)

2138C2 — Maple and Tree Beauty (Hard Version)

2139D — Antiamuny and Slider Movement

2139E1 — Determinant Construction (Easy Version)

2139E2 — Determinant Construction (Hard Version)

2139F — Ode to the Bridge Builder

For convenience, we mark the targets point and the points on the initial segment with $$$A(0,0),B(1,0),C(p,q)$$$.

The problem asks us to do at most $$$\left\lceil 2|AC|\right\rceil$$$ moves. This constraint is actually not quite usual. We can first show that the theoretical lower bound should be $$$x=\left\lceil |AC|\right\rceil+\left\lceil |BC|\right\rceil−1$$$. We can show we can't get less moves by following: If we have already constructed the final structure, then $$$AC$$$ and $$$BC$$$ should be connected with a path, and we can find a path from $$$A$$$ to $$$C$$$ and a path from $$$B$$$ to $$$C$$$ that don't intersect (except at point $$$C$$$), otherwise the structure can't be built with non-degenerate triangles.

And we have to alternate progressing through two paths every time we construct a triangle, otherwise we must draw a line longer than $$$1$$$. The last triangle will cover both paths, so the number of steps will be decreased by one. The optimal path is two straight segments (which is not always possible).

\textbf{Case 1.1:} We first try some simple strategies. Two triangles can form a parallelogram, so we can connect $$$AC$$$, choose a point $$$D$$$ on $$$AC$$$ which makes $$$|AD|=\frac{|AC|}{\lceil|AC|\rceil}$$$, which is always in range $$$[0.5,1]$$$ when $$$|AC|\ge 1$$$. And from $$$\triangle ADB$$$ we can construct a parallelogram. We draw a line passing $$$D$$$ that is parallel to $$$AB$$$, a line passing $$$B$$$ that is parallel to $$$AC$$$, and they intersects at $$$E$$$. Then we pile up the same parallelogram structure until we reach $$$C$$$. This always works when $$$30^\circ\le\angle CAB\le60^\circ$$$.

Proof: We first prove that all segments has length between $$$0.5$$$ and $$$1$$$. Because we stack the same parallelogram structure, all segments have length equal to $$$AB,BD$$$ or $$$AD$$$. $$$AB$$$ and $$$AD$$$ already meets the requirement. When $$$30^\circ\le\angle CAB\le60^\circ$$$, the length of $$$BD$$$ is at least $$$0.5$$$ as the distance between two parallel lines is at least $$$0.5$$$, and at most $$$1$$$ as $$$AB=1$$$ and $$$\angle CAB$$$ is never the largest angle in $$$\triangle DAB$$$. We can calculate that the number of moves we used is $$$2\left\lceil |AC|\right\rceil-1\le\left\lceil 2|AC|\right\rceil$$$ which matches the requirement (for the last parallelogram we only need one triangle).

![](https://s21.ax1x.com/2025/09/07/pV2wJnU.png)

\textbf{Case 1.2:} We can change the way we construct parallelograms (with sides $$$AB,BC$$$) and this method always works when $$$30^\circ\le\angle CBx\le60^\circ$$$. The number of moves is $$$\left\lceil2|BC|\right\rceil\le \left\lceil 2|AC|\right\rceil$$$. This case is actually necessary, which will be explained in the following part.

![](https://s21.ax1x.com/2025/09/07/pV204IJ.png)

\textbf{Case 2:} If $$$\angle CAB \lt \angle CBx \lt 30^\circ$$$. We first build a point $$$D$$$ which makes $$$AD=1$$$ and $$$\angle DAB=30^\circ$$$ and construct $$$\triangle DAB$$$.

We can show that the constraint is actually easier to meet in this situation, because when $$$\angle CAB \lt \angle CBx \lt 30^\circ$$$, $$$|BC| \lt |AC|-0.5$$$. With this, $$$\left\lceil |AC|\right\rceil+\left\lceil |BC|\right\rceil−1=\left\lceil 2|AC|\right\rceil-1$$$ always holds, allowing us one extra move.

Then we draw a line passing $$$D$$$ parallel to $$$BC$$$. We can show that if $$$\angle DAB=30^\circ$$$ and $$$0\le \angle CAB\le 30^\circ$$$, the distance from $$$D$$$ to line $$$BC$$$ is at least $$$0.5$$$. So all segments with ends on different lines will have length $$$\ge 0.5$$$.

Then we select a point $$$E$$$ on $$$BC$$$, which makes $$$DE=1$$$. We can show that $$$\sqrt{3}-1\le |BE|\le 1$$$ based on some calculations in this case. Then we do a similar parallelogram construction process to $$$C$$$. The total number of moves is $$$2\left\lceil |CE|\right\rceil+2$$$.

There are still two cases here to analyze to prove the number of steps fulfills our requirement. We write $$$|BC|=a+b$$$ where $$$a$$$ is the integer part of $$$|BC|$$$, then we analyze cases about $$$b$$$.

  • Case 2.1: When $$$b\ge\sqrt{3}-1$$$ or $$$b=0$$$, we can show that $$$2\left\lceil |AC|\right\rceil=\left\lceil 2|AC|\right\rceil$$$, and $$$\left\lceil |AC|\right\rceil=\left\lceil |BC|\right\rceil+1$$$ if $$$|AC|\ge 2$$$. The number of steps is $$$2\left\lceil |EC|\right\rceil+2\le 2\left\lceil |BC|\right\rceil+2=2\left\lceil |AC|\right\rceil$$$.

  • Case 2.2: When $$$0 \lt b \lt \sqrt{3}-1$$$, we can show that $$$\left\lceil |EC|\right\rceil=\left\lceil |BC|\right\rceil-1$$$. Total moves equals to $$$2+2\left\lceil |CE|\right\rceil=2\left\lceil |BC|\right\rceil\le \left\lceil |AC|\right\rceil+\left\lceil |BC|\right\rceil=\left\lceil 2|AC|\right\rceil$$$.

Be careful with small cases where $$$|BC|$$$ is too short, which may make $$$|DF|=|EG| \lt 0.5$$$.

Note that there are some cases where $$$\angle CBx \gt 30^\circ$$$ and $$$\angle CAB \lt 30^\circ$$$, where Case 2 strategy doesn't work. So case 1.2 is required.

![](https://s21.ax1x.com/2025/09/07/pV2wUAJ.png)

\textbf{Case 3:} If $$$\angle CBx \gt \angle CAB \gt 60^\circ$$$. We first build a point $$$D$$$ which makes $$$AD=1$$$ and $$$\angle DAB=60^\circ$$$ and construct $$$\triangle DAB$$$. We write $$$|AC|=a+b$$$ where $$$a$$$ is integer, then we analyze two cases about $$$b$$$.

  • \textbf{Case 3.1:} When $$$b \gt 0.5$$$ or $$$b=0$$$, $$$2\left\lceil |AC|\right\rceil=\left\lceil 2|AC|\right\rceil$$$. We begin a same parallelogram construction as Case 1 where the sides of parallelogram are $$$BC,BD$$$. We can show that $$$30^\circ\le\angle CBD\le60^\circ$$$. So it is possible to pile up to $$$C$$$ from $$$BD$$$ in $$$2\left\lceil |BC|\right\rceil-1$$$ moves. And in total we need $$$2\left\lceil |BC|\right\rceil\le2\left\lceil |AC|\right\rceil=\left\lceil 2|AC|\right\rceil$$$ moves.

![](https://s21.ax1x.com/2025/09/07/pV2wYBF.png)

  • \textbf{Case 3.2:} When $$$0 \lt b\le 0.5$$$, $$$2\left\lceil |AC|\right\rceil=\left\lceil 2|AC|\right\rceil+1$$$. We instead connect $$$CD$$$ and construct parallelogram with sides $$$DC,DB$$$. We can show that $$$120^\circ\le\angle CDB\le150^\circ$$$ so we can still do the parallelogram construction. When $$$|AC|\ge \sqrt{3}$$$, $$$\left\lceil |CD|\right\rceil=\left\lceil |AC||\right\rceil-1$$$, making the number of moves $$$2\left\lceil |CD|\right\rceil+1=2\left\lceil |AC|\right\rceil-1=\left\lceil 2|AC|\right\rceil$$$.

![](https://s21.ax1x.com/2025/09/07/pV2wt74.png)

Actually case 1.1 is not required, because it is impossible to construct a testcase where $$$\angle CAB \lt 60^\circ, \angle CBx \gt 60^\circ,0 \lt b\le 0.5$$$ and Case 3.2 fails.

#include <bits/stdc++.h>
using namespace std;
typedef double db;
const db pi = acos(-1.0);
const int N = 1000005;

inline int sgn(db x){
    if(x < 1e-13 && x > -1e-13) return 0;
    if(x > 0) return 1;
    return -1;
}

struct point{
    db x,y;
    point (db _x = 0.0,db _y = 0.0) : x(_x), y(_y) {}
};
point operator + (const point &p1,const point &p2){
	return point(p1.x + p2.x,p1.y + p2.y);
}
point operator - (const point &p1,const point &p2){
	return point(p1.x - p2.x,p1.y - p2.y);
}
point operator * (db x,const point &p){
	return point(x * p.x,x * p.y);
} 
bool operator == (point x,point y){
	return sgn(x.x - y.x) == 0 && sgn(x.y - y.y) == 0;
}

inline db dot(point p1,point p2){
    return p1.x * p2.x + p1.y * p2.y;
}

inline db det(point p1,point p2){
	return p1.x * p2.y - p2.x * p1.y;
}

inline db len(point p){
    return sqrtl(1.0 * p.x * p.x + 1.0 * p.y * p.y);
}

point project_point(point x,point ya,point yb){
	point v = yb - ya;
	return ya + (dot(v,x - ya) / dot(v,v)) * v;
}

db distp(point x,point ya,point yb){
	return fabs(det(ya - x,yb - x)) / len(yb - ya);
}

point line_circle_intersec_point(point o,point la,point lb){
	db dis = distp(o,la,lb),l;
	point pj = project_point(o,la,lb);
	l = sqrt(1.0 - dis * dis);
	point ret = pj + (l / len(lb - la)) * (lb - la);
	return ret;
}

tuple <int,int,int> ans[N];
point p[N],target;
int step;

bool check(int n){
    set <pair <int,int> > st;
    st.insert({1,2});
    if(n > step) return 0;
    db eps_len = 1e-8,eps_dis = 1e-4;
    int fl = 0;
    for(int i = 1;i <= n;i ++){
        auto [u,v,w] = ans[i];
        if(u > v) swap(u,v);
        if(st.find({u,v}) == st.end()) return 0;
        if(len(p[u] - p[w]) < 0.5 - eps_len || len(p[u] - p[w]) > 1.0 + eps_len) return 0;
        if(len(p[v] - p[w]) < 0.5 - eps_len || len(p[v] - p[w]) > 1.0 + eps_len) return 0;
        st.insert({u,w}); st.insert({v,w});
        if(len(p[w] - target) <= eps_dis) fl = 1;
    }
    return 1;
}

int solve1a(){
    point dir = target - p[1];
    int split = ceil(len(dir) - 1e-9);
    int c = 2;
    for(int i = 1;i < split;i ++){
        ++ c; p[c] = p[1] + (1.0 * i / split) * dir;
        ans[c - 2] = {c - 2,c - 1,c};
        ++ c; p[c] = p[2] + (1.0 * i / split) * dir;
        ans[c - 2] = {c - 2,c - 1,c};
        // construct one parallelogram
    }
    ++ c; p[c] = target;
    ans[c - 2] = {c - 2,c - 1,c};
    if(check(c - 2)) return c - 2;
    return 0;
}

int solve1b(){
    point dir = target - p[2];
    int split = ceil(len(dir) - 1e-9);
    int c = 2;
    for(int i = 1;i <= split;i ++){
        ++ c; p[c] = p[1] + (1.0 * i / split) * dir;
        ans[c - 2] = {c - 2,c - 1,c};
        ++ c; p[c] = p[2] + (1.0 * i / split) * dir;
        ans[c - 2] = {c - 2,c - 1,c};
    }
    if(check(c - 2)) return c - 2;
    return 0;
}

int solve2(){
    p[3] = point(sqrt(3.0) / 2,0.5);
    p[4] = line_circle_intersec_point(p[3],p[2],target);
    if(len(p[4] - p[2]) > 1)
        p[4] = p[2] + (1.0 / len(target - p[2])) * (target - p[2]);
    ans[1] = {1,2,3};
    ans[2] = {2,3,4};
    point dir = target - p[4];
    int split = ceil(len(dir) - 1e-9);
    int c = 4;
    for(int i = 1;i <= split;i ++){
        ++ c; p[c] = p[3] + (1.0 * i / split) * dir;
        ans[c - 2] = {c - 2,c - 1,c};
        ++ c; p[c] = p[4] + (1.0 * i / split) * dir;
        ans[c - 2] = {c - 2,c - 1,c};
    }
    if(check(c - 2)) return c - 2;
    return 0;
}

int solve3a(){
    p[3] = point(0.5,sqrt(3.0) / 2);
    ans[1] = {1,2,3};
    point dir = target - p[2];
    int split = ceil(len(dir) - 1e-9);
    int c = 3;
    for(int i = 1;i < split;i ++){
        ++ c; p[c] = p[2] + (1.0 * i / split) * dir;
        ans[c - 2] = {c - 2,c - 1,c};
        ++ c; p[c] = p[3] + (1.0 * i / split) * dir;
        ans[c - 2] = {c - 2,c - 1,c};
    }
    ++ c; p[c] = target;
    ans[c - 2] = {c - 2,c - 1,c};
    if(check(c - 2)) return c - 2;
    return 0;
}

int solve3b(){
    p[3] = point(0.5,sqrt(3.0) / 2);
    ans[1] = {1,2,3};
    point dir = target - p[3];
    int split = ceil(len(dir) - 1e-9);
    int c = 3;
    for(int i = 1;i <= split;i ++){
        ++ c; p[c] = p[2] + (1.0 * i / split) * dir;
        ans[c - 2] = {c - 2,c - 1,c};
        ++ c; p[c] = p[3] + (1.0 * i / split) * dir;
        ans[c - 2] = {c - 2,c - 1,c};
    }
    if(check(c - 2)) return c - 2;
    return 0;
}

int solve(){
    if(int res = solve1a()) return res;
    if(int res = solve1b()) return res;
    if(int res = solve2()) return res;
    if(int res = solve3a()) return res;
    if(int res = solve3b()) return res;
    return 0;
}

int main(){
    int TC; scanf("%d",&TC);
    p[1] = point(0,0);
    p[2] = point(1,0);
    while(TC --){
        int tx,ty;
        scanf("%d %d %d",&tx,&ty,&step);
        step = ceil(2.0 * sqrt(1.0 * tx * tx + 1.0 * ty * ty));
        target = point(tx,ty);
        int n = solve();
        assert(n > 0);
        printf("%d\n",n);
        for(int i = 1;i <= n;i ++){
            auto [u,v,w] = ans[i];
            printf("%d %d %.12lf %.12lf\n",u,v,p[w].x,p[w].y);
        }
    }
    return 0;
}

История

 
 
 
 
Правки
 
 
  Rev. Язык Кто Когда Δ Комментарий
en33 Английский installb 2025-09-09 19:46:59 0 (published)
en32 Английский installb 2025-09-09 19:43:46 23
en31 Английский installb 2025-09-09 19:40:59 27
en30 Английский installb 2025-09-09 19:34:14 51 (saved to drafts)
en29 Английский installb 2025-09-08 23:47:06 0 (published)
en28 Английский installb 2025-09-08 23:46:22 18
en27 Английский installb 2025-09-08 23:45:53 25
en26 Английский installb 2025-09-08 23:42:42 68
en25 Английский installb 2025-09-08 23:41:12 960
en24 Английский installb 2025-09-08 23:39:17 850
en23 Английский installb 2025-09-08 23:37:43 85
en22 Английский installb 2025-09-08 23:36:46 160
en21 Английский installb 2025-09-08 23:24:43 8140
en20 Английский installb 2025-09-08 23:23:08 8644 Reverted to en14
en19 Английский installb 2025-09-08 23:22:08 67
en18 Английский installb 2025-09-08 23:20:21 64
en17 Английский installb 2025-09-08 23:14:11 62
en16 Английский installb 2025-09-08 23:13:02 103
en15 Английский installb 2025-09-08 23:11:29 8424
en14 Английский wjy666 2025-09-08 22:43:26 5984
en13 Английский installb 2025-09-08 22:30:36 9
en12 Английский installb 2025-09-08 22:27:35 896
en11 Английский installb 2025-09-08 22:21:03 29
en10 Английский installb 2025-09-08 22:20:01 1173
en9 Английский installb 2025-09-08 22:13:25 291
en8 Английский installb 2025-09-08 22:08:55 3404
en7 Английский installb 2025-09-08 21:06:11 18537
en6 Английский installb 2025-09-08 20:58:41 82
en5 Английский installb 2025-09-08 20:57:39 2532
en4 Английский installb 2025-09-08 20:50:17 2041
en3 Английский installb 2025-09-08 20:47:06 13186
en2 Английский installb 2025-09-08 20:44:29 913 Tiny change: '1' -> '\n~~~~~\nYour code here...\n~~~~~\n\n``'
en1 Английский installb 2025-09-08 19:38:01 10 Initial revision (saved to drafts)