Problem:
Problem G:
Neko's Treasure
Maki is a house cat. One day she fortunately came at a wonderful-looking dried fish. Since she
felt not hungry on that day, she put it up in her bed. However there was a problem; a rat was
living in her house, and he was watching for a chance to steal her food. To secure the fish during
the time she is asleep, she decided to build some walls to prevent the rat from reaching her bed.
Maki's house is represented as a two-dimensional plane. She has hidden the dried fish at (
x
t
,
y
t
).
She knows that the lair of the rat is located at (
x
s
,
y
s
). She has some candidate locations to
build walls. The
i
-th candidate is described by a circle of radius
r
i
centered at (
x
i
,
y
i
). She can
build walls at as many candidate locations as she wants, unless they touch or cross each other.
You can assume that the size of the fish, the rat’s lair, and the thickness of walls are all very
small and can be ignored.
Your task is to write a program which determines the minimum number of walls the rat needs
to climb over until he can get to Maki's bed from his lair, assuming that Maki made an optimal
choice of walls.
Input
The input is a sequence of datasets. Each dataset corresponds to a single situation and has the following format:
n
x
s
y
s
x
t
y
t
x
1
y
1
r
1
...
x
n
y
n
r
n
n
is the number of candidate locations where to build walls (1 ≤
n
≤ 1000). (
x
s
,
y
s
) and (
x
t
,
y
t
)
denote the coordinates of the rat's lair and Maki's bed, respectively. The
i
-th candidate location
is a circle which has radius
r
i
(1 ≤
r
i
≤ 10000) and is centered at (
x
i
,
y
i
) (
i
= 1, 2, ... ,
n
). All
coordinate values are integers between 0 and 10000 (inclusive).
All candidate locations are distinct and contain neither the rat's lair nor Maki's bed. The
positions of the rat's lair and Maki's bed are also distinct.
The input is terminated by a line with "
0
". This is not part of any dataset and thus should not
be processed.
Output
For each dataset, print a single line that contains the minimum number of walls the rat needs
to climb over.
Sample Input
3
0 0 100 100
60 100 50
100 100 10
80 80 50
4
0 0 100 100
50 50 50
150 50 50
50 150 50
150 150 50
0
Output for the Sample Input
2
0

Submitted solutions:

code_snippet: #include <stdio.h>
#include <math.h>
#include <string.h>
#include <stdlib.h>

typedef struct _c {
        int x,y,r;
}circle;

const double LIT=1e-6;

circle p1[2000],p2[2000];
int dp1[2000], dp2[2000];

int cmp(const void *a, const void *b) {
        return (((const circle*)a)->r)-(((const circle*)b)->r);
}

double dis(circle a, circle b) {
        return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}

int c_isin(circle a, circle b) {
        return dis(a,b)+LIT<abs(a.r-b.r);
}

int p_isin(int x, int y, circle b) {
        circle a;
        a.x=x;a.y=y;a.r=0;
        return c_isin(a,b);
}

int touch(circle a, circle b) {
        double d = dis(a,b);
        return d-LIT<abs(a.r+b.r);
}

int max(int a,int b) {
        return (a>b)?a:b;
}

void lis(int dp[], circle t[], int n) {
        int i,j,k,l;
        memset(dp, 0, sizeof(dp));
        qsort(t+1,n,sizeof(circle), cmp);
        for(i=1;i<=n;i++) {
                dp[i] = 1;
                for(j=1;j<i;j++) {
                        if(c_isin(t[i],t[j])) {
                                dp[i]=max(dp[i], dp[j]+1);
                        }
                }
        }
}

int main(void) {
        int i,j,k,l,n1,n2,n;
        int sol=0;
        int x,y,r;
        int xs,ys,xt,yt;
        circle t;
        while(1) {
                sol=0;
                scanf("%d", &n);
                if(n==0) {
                        break;
                }
                scanf("%d%d%d%d", &xs, &ys, &xt, &yt);
                n1=0;
                n2=0;
                for(i=1;i<=n;i++) {
                        k=0;l=0;
                        scanf("%d%d%d", &t.x, &t.y, &t.r);
                        k=p_isin(xs,ys, t);
                        l=p_isin(xt,yt,t);
                        if(k&&!l) {
                                p1[++n1]=t;
                        }
                        else if(!k&&l) {
                                p2[++n2]=t;
                        }
                }
                lis(dp1, p1,n1);
                lis(dp2,p2,n2);
                for(i=1;i<=n1;i++) {
                        for(j=1;j<=n2;j++) {
                                if(!touch(p1[i],p2[j])) {
                                        sol=max(sol, dp1[i]+dp2[j]);
                                }
                        }
                }
                for(i=1;i<=n1;i++) {
                        sol=max(sol, dp1[i]);
                }
                for(i=1;i<=n2;i++) {
                        sol=max(sol,dp2[i]);
                }
                printf("%d\n", sol);
        }
        return 0;
}
accuracy: 1
time_ms: 30
memory_kb: 2856
final_rank: 1

code_snippet: #include <bits/stdc++.h>

using namespace std;

#define rep(i, a, b) for (ll i = (ll)(a); i < (ll)(b); i++)
#define rrep(i, a, b) for (ll i = (ll)(b)-1; i >= (ll)(a); i--)
#define ALL(v) (v).begin(), (v).end()
#define UNIQUE(v) sort(ALL(v)), (v).erase(unique(ALL(v)), (v).end())
#define SZ(v) (int)v.size()
#define MIN(v) *min_element(ALL(v))
#define MAX(v) *max_element(ALL(v))
#define LB(v, x) int(lower_bound(ALL(v), (x)) - (v).begin())
#define UB(v, x) int(upper_bound(ALL(v), (x)) - (v).begin())

using uint = unsigned int;
using ll = long long int;
using ull = unsigned long long;
using i128 = __int128_t;
using u128 = __uint128_t;
const int inf = 0x3fffffff;
const ll INF = 0x1fffffffffffffff;

template <typename T> inline bool chmax(T &a, T b) {
    if (a < b) {
        a = b;
        return 1;
    }
    return 0;
}
template <typename T> inline bool chmin(T &a, T b) {
    if (a > b) {
        a = b;
        return 1;
    }
    return 0;
}
template <typename T, typename U> T ceil(T x, U y) {
    assert(y != 0);
    if (y < 0)
        x = -x, y = -y;
    return (x > 0 ? (x + y - 1) / y : x / y);
}
template <typename T, typename U> T floor(T x, U y) {
    assert(y != 0);
    if (y < 0)
        x = -x, y = -y;
    return (x > 0 ? x / y : (x - y + 1) / y);
}
template <typename T> int popcnt(T x) {
    return __builtin_popcountll(x);
}
template <typename T> int topbit(T x) {
    return (x == 0 ? -1 : 63 - __builtin_clzll(x));
}
template <typename T> int lowbit(T x) {
    return (x == 0 ? -1 : __builtin_ctzll(x));
}

template <class T, class U>
ostream &operator<<(ostream &os, const pair<T, U> &p) {
    os << "P(" << p.first << ", " << p.second << ")";
    return os;
}
template <typename T> ostream &operator<<(ostream &os, const vector<T> &vec) {
    os << "{";
    for (int i = 0; i < vec.size(); i++) {
        os << vec[i] << (i + 1 == vec.size() ? "" : ", ");
    }
    os << "}";
    return os;
}
template <typename T, typename U>
ostream &operator<<(ostream &os, const map<T, U> &map_var) {
    os << "{";
    for (auto itr = map_var.begin(); itr != map_var.end(); itr++) {
        os << "(" << itr->first << ", " << itr->second << ")";
        itr++;
        if (itr != map_var.end())
            os << ", ";
        itr--;
    }
    os << "}";
    return os;
}
template <typename T> ostream &operator<<(ostream &os, const set<T> &set_var) {
    os << "{";
    for (auto itr = set_var.begin(); itr != set_var.end(); itr++) {
        os << *itr;
        ++itr;
        if (itr != set_var.end())
            os << ", ";
        itr--;
    }
    os << "}";
    return os;
}
#ifdef LOCAL
#define show(...) _show(0, #__VA_ARGS__, __VA_ARGS__)
#else
#define show(...) true
#endif
template <typename T> void _show(int i, T name) {
    cerr << '\n';
}
template <typename T1, typename T2, typename... T3>
void _show(int i, const T1 &a, const T2 &b, const T3 &...c) {
    for (; a[i] != ',' && a[i] != '\0'; i++)
        cerr << a[i];
    cerr << ":" << b << " ";
    _show(i + 1, a, c...);
}

/**
 * @brief template
 */

struct Point {
    double X, Y;
};

struct Circle {
    Point P;
    double R;
    Circle(Point p, double r) : P(p), R(r) {};
};

double sq(double D) {
    return D*D;
}

double normPP(Point P, Point Q) {
    return sq(P.X-Q.X) + sq(P.Y-Q.Y);
}

bool ContainCP(Circle C, Point P) {
    return normPP(C.P,P) < sq(C.R);
}

bool ContainCC(Circle C1, Circle C2) { // C1 in C2
    double D = sqrt(normPP(C1.P,C2.P));
    return D + C1.R < C2.R;
}

bool notintersect(Circle C1, Circle C2) {
    double D = sqrt(normPP(C1.P,C2.P));
    return C1.R + C2.R < D;
}

int main() {
while(1) {
    int N;
    cin >> N;
    if (N == 0) return 0;
    Point A, B;
    cin >> A.X >> A.Y >> B.X >> B.Y;
    vector<Circle> S, T;
    S.push_back(Circle(A,0.0));
    T.push_back(Circle(B,0.0));
    rep(i,0,N) {
        Point P;
        double R;
        cin >> P.X >> P.Y >> R;
        Circle C(P,R);
        bool checkA = ContainCP(C,A), checkB = ContainCP(C,B);
        if (checkA == checkB) continue;
        if (checkA) S.push_back(C);
        if (checkB) T.push_back(C);
    }
    N = S.size();
    int M = T.size();
    sort(ALL(S),[](Circle C1, Circle C2){return C1.R < C2.R;});
    sort(ALL(T),[](Circle C1, Circle C2){return C1.R < C2.R;});
    vector<int> DPS(N,0), DPT(M,0);
    rep(i,1,N) {
        rep(j,0,i) {
            if (ContainCC(S[j],S[i])) chmax(DPS[i],DPS[j]+1);
        }
    }
    rep(i,0,M) {
        rep(j,0,i) {
            if (ContainCC(T[j],T[i])) chmax(DPT[i],DPT[j]+1);
        }
    }
    int ANS = 0;
    rep(i,0,N) {
        rep(j,0,M) {
            if (notintersect(S[i],T[j])) chmax(ANS,DPS[i]+DPT[j]);
        }
    }
    cout << ANS << endl;
}
}
accuracy: 1
time_ms: 20
memory_kb: 3460
final_rank: 10

code_snippet: #include <bits/stdc++.h>
using namespace std;
#define rng(i, l, r) for(int i = int(l); i < int(r); i++)
#define rep(i, n) rng(i, 0, n)
using ll = long long;
#define sz(v) int(v.size())
#define all(v) v.begin(), v.end()
using ld = long double;
using point = complex<ld>;
point input_pt() {
	ld x, y;
	cin >> x >> y;
	return point(x, y);
}
template <class T>
bool chmax(T& a, T b) {
	return a < b ? a = b, 1 : 0;
}
int n;
void solve() {
	point start = input_pt();
	point goal = input_pt();

	vector<pair<ld, point>> circs(n);

	vector<pair<ld, point>> contain_start, contain_goal;

	auto contain = [](point p, point center, ld radius) { return abs(p - center) < radius; };

	rep(i, n) {
		point center = input_pt();
		ld radius;
		cin >> radius;
		bool cont_s = contain(start, center, radius);
		bool cont_g = contain(goal, center, radius);
		if(cont_s) {
			if(!cont_g) contain_start.emplace_back(radius, center);
		} else if(cont_g) {
			contain_goal.emplace_back(radius, center);
		}
	}

	auto cmp = [](const pair<ld, point>& a, const pair<ld, point>& b) { return a.first < b.first; };
	auto slv = [&cmp](vector<pair<ld, point>>& walls) {
		sort(all(walls), cmp);
		int ws = sz(walls);
		vector<int> ans(ws, 1);

		auto include = [&walls](int small, int large) -> bool {
			point cs, cl;
			ld rs, rl;
			tie(rs, cs) = walls[small];
			tie(rl, cl) = walls[large];
			ld d = abs(cs - cl);
			return d + rs < rl;
		};

		rep(i, ws) {
			rng(j, i + 1, ws) {
				if(include(i, j)) { chmax(ans[j], ans[i] + 1); }
			}
		}
		return ans;
	};

	vector<int> s = slv(contain_start);
	vector<int> g = slv(contain_goal);

	int ans = 0;
	if(s.size()) ans = *max_element(all(s));
	if(g.size()) chmax(ans, *max_element(all(g)));

	if(sz(s) && sz(g)) {
		rep(i, sz(s)) rep(j, sz(g)) {
			auto& fs = contain_start[i];
			auto& fg = contain_goal[j];

			if(fs.first + fg.first < abs(fs.second - fg.second)) { chmax(ans, s[i] + g[j]); }
		}
	}

	cout << ans << endl;
}
int main() {
	while(cin >> n && n) solve();
}
accuracy: 1
time_ms: 160
memory_kb: 3628
final_rank: 13

code_snippet: #include <iostream>
#include <algorithm>
#include <vector>
using namespace std;

bool check_surround(int x, int y, int p, int q, int r) {
    return (r*r > ((x-p)*(x-p)+(y-q)*(y-q)));
}

bool check_cross(int x1, int y1, int r1, int x2, int y2, int r2) {
    return ((r1-r2)*(r1-r2) <= ((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)) && ((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)) <= (r1+r2)*(r1+r2));
}

struct Circle {
    Circle(int x, int y, int r, int include) : x{x}, y{y}, r{r}, include{include} {}
    int x;
    int y;
    int r;
    int include;
};

bool compare(Circle &l, Circle &r) {
    return l.r < r.r;
}

int main() {
    int N;
    while (cin >> N && N > 0) {
        vector<Circle> rat_data;
        vector<Circle> Maki_data;
        int xs,ys,xt,yt;
        cin >> xs >> ys >> xt >> yt;
        for (int i=0; i<N; ++i) {
            int x,y,r;
            cin >> x >> y >> r;
            if (check_surround(x,y,xs,ys,r) || check_surround(x,y,xt,yt,r)) {
                Circle d(x,y,r,1);
                if (!check_surround(x,y,xt,yt,r)) {
                    rat_data.push_back(d);
                } else if (!check_surround(x,y,xs,ys,r)) {
                    Maki_data.push_back(d);
                }
            }
        }
        sort(rat_data.begin(), rat_data.end(), compare);
        sort(Maki_data.begin(), Maki_data.end(), compare);
        for (int i=0; i<rat_data.size(); ++i) {
            for (int j=0; j<i; ++j) {
                if (!check_cross(rat_data[i].x,rat_data[i].y,rat_data[i].r,rat_data[j].x,rat_data[j].y,rat_data[j].r)) {
                    if (rat_data[i].include <= rat_data[j].include) rat_data[i].include = rat_data[j].include+1;
                }
            }
        }
        for (int i=0; i<Maki_data.size(); ++i) {
            for (int j=0; j<i; ++j) {
                if (!check_cross(Maki_data[i].x,Maki_data[i].y,Maki_data[i].r,Maki_data[j].x,Maki_data[j].y,Maki_data[j].r)) {
                    if (Maki_data[i].include <= Maki_data[j].include) Maki_data[i].include = Maki_data[j].include+1;
                }
            }
        }
        int max = 0;
        if (rat_data.size() == 0) {
            if (Maki_data.size() == 0) {
                max = 0;
            } else {for (int i=0; i<Maki_data.size(); ++i) {
                    if (max < Maki_data[i].include)
                        max = Maki_data[i].include;
                }
            }
        } else {
            if (Maki_data.size() == 0) {
                for (int i=0; i<rat_data.size(); ++i) {
                    if (max < rat_data[i].include)
                        max = rat_data[i].include;
                }
            } else {
                for (int i=0; i<rat_data.size(); ++i) {
                    if (max < rat_data[i].include)
                        max = rat_data[i].include;
                }
                for (int i=0; i<Maki_data.size(); ++i) {
                    if (max < Maki_data[i].include)
                        max = Maki_data[i].include;
                }
                for (int i=0; i<rat_data.size(); ++i) {
                    for (int j=0; j<Maki_data.size(); ++j) {
                        if (!check_cross(rat_data[i].x,rat_data[i].y,rat_data[i].r,Maki_data[j].x,Maki_data[j].y,Maki_data[j].r)) {
                            if (max < (rat_data[i].include + Maki_data[j].include))
                                max = rat_data[i].include + Maki_data[j].include;
                        }
                    }
                }
            }
        }
        cout << max << endl;
    }
}
accuracy: 1
time_ms: 10
memory_kb: 3404
final_rank: 6

code_snippet: #include <iostream>
#include <algorithm>
#include <vector>
#include <cmath>
using namespace std;

bool check_surround(int x, int y, int p, int q, int r) {
    return (r*r > ((x-p)*(x-p)+(y-q)*(y-q)));
}

bool check_cross(int x1, int y1, int r1, int x2, int y2, int r2) {
    return ((r1-r2)*(r1-r2) <= ((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)) && ((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)) <= (r1+r2)*(r1+r2));
}

/*
struct Circle {
    Circle(int x, int y, int r, double dist_rat, double dist_Maki, int include) : x{x}, y{y}, r{r}, dist_rat{dist_rat}, dist_Maki{dist_Maki}, include{include} {}
    int x;
    int y;
    int r;
    double dist_rat;
    double dist_Maki;
    int include;
};
*/
struct Circle {
    Circle(int x, int y, int r, int include) : x{x}, y{y}, r{r}, include{include} {}
    int x;
    int y;
    int r;
    int include;
};

/*
bool compare_rat(Circle &l, Circle &r) {
    if (l.dist_rat != r.dist_rat) return l.dist_rat < r.dist_rat;
    else return l.r < r.r;
}

bool compare_Maki(Circle &l, Circle &r) {
    if (l.dist_Maki != r.dist_Maki) return l.dist_Maki < r.dist_Maki;
    else return l.r < r.r;
}
*/
bool compare(Circle &l, Circle &r) {
    return l.r < r.r;
}
/*
int main() {
    int N;
    while (cin >> N && N > 0) {
        vector<Circle> rat_data;
        vector<Circle> Maki_data;
        int xs,ys,xt,yt;
        cin >> xs >> ys >> xt >> yt;
        for (int i=0; i<N; ++i) {
            int x,y,r;
            cin >> x >> y >> r;
            if (check_surround(x,y,xs,ys,r) || check_surround(x,y,xt,yt,r)) {
                if (!check_surround(x,y,xt,yt,r)) {
                    Circle d(x,y,r,r-sqrt((x-xs)*(x-xs)+(y-ys)*(y-ys)),sqrt((x-xt)*(x-xt)+(y-yt)*(y-yt))-r,1);
                    rat_data.push_back(d);
                }
                else if (!check_surround(x,y,xs,ys,r)) {
                    Circle d(x,y,r,sqrt((x-xs)*(x-xs)+(y-ys)*(y-ys)),r-sqrt((x-xt)*(x-xt)+(y-yt)*(y-yt)),1);
                    Maki_data.push_back(d);
                }
            }
        }
        sort(rat_data.begin(), rat_data.end(), compare_rat);
        sort(Maki_data.begin(), Maki_data.end(), compare_Maki);
        for (int i=0; i<rat_data.size(); ++i) {
            for (int j=0; j<i; ++j) {
                if (!check_cross(rat_data[i].x,rat_data[i].y,rat_data[i].r,rat_data[j].x,rat_data[j].y,rat_data[j].r)) {
                    if (rat_data[i].include <= rat_data[j].include) rat_data[i].include = rat_data[j].include+1;
                }
            }
        }
        for (int i=0; i<Maki_data.size(); ++i) {
            for (int j=0; j<i; ++j) {
                if (!check_cross(Maki_data[i].x,Maki_data[i].y,Maki_data[i].r,Maki_data[j].x,Maki_data[j].y,Maki_data[j].r)) {
                    if (Maki_data[i].include <= Maki_data[j].include) Maki_data[i].include = Maki_data[j].include+1;
                }
            }
        }
        int max = 0;
        if (rat_data.size() == 0) {
            if (Maki_data.size() == 0) {
                max = 0;
            } else {
                for (int i=0; i<Maki_data.size(); ++i) {
                    if (max < Maki_data[i].include)
                        max = Maki_data[i].include;
                }
            }
        } else {
            if (Maki_data.size() == 0) {
                for (int i=0; i<rat_data.size(); ++i) {
                    if (max < rat_data[i].include)
                        max = rat_data[i].include;
                }
            } else {
                for (int i=0; i<rat_data.size(); ++i) {
                    if (max < rat_data[i].include)
                        max = rat_data[i].include;
                }
                for (int i=0; i<Maki_data.size(); ++i) {
                    if (max < Maki_data[i].include)
                        max = Maki_data[i].include;
                }
                for (int i=0; i<rat_data.size(); ++i) {
                    for (int j=0; j<Maki_data.size(); ++j) {
                        if (!check_cross(rat_data[i].x,rat_data[i].y,rat_data[i].r,Maki_data[j].x,Maki_data[j].y,Maki_data[j].r)) {
                            if (max < (rat_data[i].include + Maki_data[j].include))
                                max = rat_data[i].include + Maki_data[j].include;
                        }
                    }
                }
            }
        }
        cout << max << endl;
    }
}
*/
int main() {
    int N;
    while (cin >> N && N > 0) {
        vector<Circle> rat_data;
        vector<Circle> Maki_data;
        int xs,ys,xt,yt;
        cin >> xs >> ys >> xt >> yt;
        for (int i=0; i<N; ++i) {
            int x,y,r;
            cin >> x >> y >> r;
            if (check_surround(x,y,xs,ys,r) || check_surround(x,y,xt,yt,r)) {
                Circle d(x,y,r,1);
                if (!check_surround(x,y,xt,yt,r)) {
                    rat_data.push_back(d);
                } else if (!check_surround(x,y,xs,ys,r)) {
                    Maki_data.push_back(d);
                }
            }
        }
        sort(rat_data.begin(), rat_data.end(), compare);
        sort(Maki_data.begin(), Maki_data.end(), compare);
        for (int i=0; i<rat_data.size(); ++i) {
            for (int j=0; j<i; ++j) {
                if (!check_cross(rat_data[i].x,rat_data[i].y,rat_data[i].r,rat_data[j].x,rat_data[j].y,rat_data[j].r)) {
                    if (rat_data[i].include <= rat_data[j].include) rat_data[i].include = rat_data[j].include+1;
                }
            }
        }
        for (int i=0; i<Maki_data.size(); ++i) {
            for (int j=0; j<i; ++j) {
                if (!check_cross(Maki_data[i].x,Maki_data[i].y,Maki_data[i].r,Maki_data[j].x,Maki_data[j].y,Maki_data[j].r)) {
                    if (Maki_data[i].include <= Maki_data[j].include) Maki_data[i].include = Maki_data[j].include+1;
                }
            }
        }
        int max = 0;
        if (rat_data.size() == 0) {
            if (Maki_data.size() == 0) {
                max = 0;
            } else {
                for (int i=0; i<Maki_data.size(); ++i) {
                    if (max < Maki_data[i].include)
                        max = Maki_data[i].include;
                }
            }
        } else {
            if (Maki_data.size() == 0) {
                for (int i=0; i<rat_data.size(); ++i) {
                    if (max < rat_data[i].include)
                        max = rat_data[i].include;
                }
            } else {
                for (int i=0; i<rat_data.size(); ++i) {
                    if (max < rat_data[i].include)
                        max = rat_data[i].include;
                }
                for (int i=0; i<Maki_data.size(); ++i) {
                    if (max < Maki_data[i].include)
                        max = Maki_data[i].include;
                }
                for (int i=0; i<rat_data.size(); ++i) {
                    for (int j=0; j<Maki_data.size(); ++j) {
                        if (!check_cross(rat_data[i].x,rat_data[i].y,rat_data[i].r,Maki_data[j].x,Maki_data[j].y,Maki_data[j].r)) {
                            if (max < (rat_data[i].include + Maki_data[j].include))
                                max = rat_data[i].include + Maki_data[j].include;
                        }
                    }
                }
            }
        }
        cout << max << endl;
    }
}
accuracy: 1
time_ms: 10
memory_kb: 3212
final_rank: 2

code_snippet: #if 0
所要時間は7時間。まずはratとMakiどちらかだけを囲む円のみを抽出してstructとして配列rat_dataとMaki_dataに保存し、それぞれratとMakiからの距離でソートして、円をいくつ囲めるかをそれぞれの円で数える。最後に、交差しない組み合わせのうちで内に囲える円の合計が多い組が選択され、その合計が答えとなる。考え方をまとめるのに時間がかかったほか、交わるかを判定する関数check_crossを間違えていたことに気づかず、とても時間がかかってしまった。check_crossでは平方根を取らず2乗のまま判定するので、誤差でつまずく心配がない。この問題では与えられる数値が全て10000以下なのでint型で良いが、大きい数値が与えられた時には上限に注意が必要である。
#endif

#include <iostream>
#include <algorithm>
#include <vector>
#include <cmath>
using namespace std;

bool check_surround(int x, int y, int p, int q, int r) {
    return (r*r > ((x-p)*(x-p)+(y-q)*(y-q)));
}

bool check_cross(int x1, int y1, int r1, int x2, int y2, int r2) {
    return ((r1-r2)*(r1-r2) <= ((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)) && ((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)) <= (r1+r2)*(r1+r2));
}

struct Circle {
    Circle(int x, int y, int r, double dist_rat, double dist_Maki, int include) : x{x}, y{y}, r{r}, dist_rat{dist_rat}, dist_Maki{dist_Maki}, include{include} {}
    int x;
    int y;
    int r;
    double dist_rat;
    double dist_Maki;
    int include;
};

bool compare_rat(Circle &l, Circle &r) {
    if (l.dist_rat != r.dist_rat) return l.dist_rat < r.dist_rat;
    else return l.r < r.r;
}

bool compare_Maki(Circle &l, Circle &r) {
    if (l.dist_Maki != r.dist_Maki) return l.dist_Maki < r.dist_Maki;
    else return l.r < r.r;
}

int main() {
    int N;
    while (cin >> N && N > 0) {
        vector<Circle> rat_data;
        vector<Circle> Maki_data;
        int xs,ys,xt,yt;
        cin >> xs >> ys >> xt >> yt;
        for (int i=0; i<N; ++i) {
            int x,y,r;
            cin >> x >> y >> r;
            if (check_surround(x,y,xs,ys,r) || check_surround(x,y,xt,yt,r)) {
                if (!check_surround(x,y,xt,yt,r)) {
                    Circle d(x,y,r,r-sqrt((x-xs)*(x-xs)+(y-ys)*(y-ys)),sqrt((x-xt)*(x-xt)+(y-yt)*(y-yt))-r,1);
                    rat_data.push_back(d);
                }
                else if (!check_surround(x,y,xs,ys,r)) {
                    Circle d(x,y,r,sqrt((x-xs)*(x-xs)+(y-ys)*(y-ys)),r-sqrt((x-xt)*(x-xt)+(y-yt)*(y-yt)),1);
                    Maki_data.push_back(d);
                }
            }
        }
        sort(rat_data.begin(), rat_data.end(), compare_rat);
        sort(Maki_data.begin(), Maki_data.end(), compare_Maki);
        for (int i=0; i<rat_data.size(); ++i) {
            for (int j=0; j<i; ++j) {
                if (!check_cross(rat_data[i].x,rat_data[i].y,rat_data[i].r,rat_data[j].x,rat_data[j].y,rat_data[j].r)) {
                    if (rat_data[i].include <= rat_data[j].include) rat_data[i].include = rat_data[j].include+1;
                }
            }
        }
        for (int i=0; i<Maki_data.size(); ++i) {
            for (int j=0; j<i; ++j) {
                if (!check_cross(Maki_data[i].x,Maki_data[i].y,Maki_data[i].r,Maki_data[j].x,Maki_data[j].y,Maki_data[j].r)) {
                    if (Maki_data[i].include <= Maki_data[j].include) Maki_data[i].include = Maki_data[j].include+1;
                }
            }
        }
        int max = 0;
        if (rat_data.size() == 0) {
            if (Maki_data.size() == 0) {
                max = 0;
            } else {
                for (int i=0; i<Maki_data.size(); ++i) {
                    if (max < Maki_data[i].include)
                        max = Maki_data[i].include;
                }
            }
        } else {
            if (Maki_data.size() == 0) {
                for (int i=0; i<rat_data.size(); ++i) {
                    if (max < rat_data[i].include)
                        max = rat_data[i].include;
                }
            } else {
                for (int i=0; i<rat_data.size(); ++i) {
                    if (max < rat_data[i].include)
                        max = rat_data[i].include;
                }
                for (int i=0; i<Maki_data.size(); ++i) {
                    if (max < Maki_data[i].include)
                        max = Maki_data[i].include;
                }
                for (int i=0; i<rat_data.size(); ++i) {
                    for (int j=0; j<Maki_data.size(); ++j) {
                        if (!check_cross(rat_data[i].x,rat_data[i].y,rat_data[i].r,Maki_data[j].x,Maki_data[j].y,Maki_data[j].r)) {
                            if (max < (rat_data[i].include + Maki_data[j].include))
                                max = rat_data[i].include + Maki_data[j].include;
                        }
                    }
                }
            }
        }
        cout << max << endl;
    }
}
accuracy: 1
time_ms: 10
memory_kb: 3264
final_rank: 3

code_snippet: #include <iostream>
#include <algorithm>
#include <vector>
#include <cmath>
using namespace std;

bool check_surround(int x, int y, int p, int q, int r) {
    return (r*r > ((x-p)*(x-p)+(y-q)*(y-q)));
}

bool check_cross(int x1, int y1, int r1, int x2, int y2, int r2) {
    return ((r1-r2)*(r1-r2) <= ((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)) && ((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)) <= (r1+r2)*(r1+r2));
}

struct Circle {
    Circle(int x, int y, int r, double dist_rat, double dist_Maki, int include) : x{x}, y{y}, r{r}, dist_rat{dist_rat}, dist_Maki{dist_Maki}, include{include} {}
    int x;
    int y;
    int r;
    double dist_rat;
    double dist_Maki;
    int include;
};

bool compare_rat(Circle &l, Circle &r) {
    if (l.dist_rat != r.dist_rat) return l.dist_rat < r.dist_rat;
    else return l.r < r.r;
}

bool compare_Maki(Circle &l, Circle &r) {
    if (l.dist_Maki != r.dist_Maki) return l.dist_Maki < r.dist_Maki;
    else return l.r < r.r;
}

int main() {
    int N;
    while (cin >> N && N > 0) {
        vector<Circle> rat_data;
        vector<Circle> Maki_data;
        int xs,ys,xt,yt;
        cin >> xs >> ys >> xt >> yt;
        for (int i=0; i<N; ++i) {
            int x,y,r;
            cin >> x >> y >> r;
            if (check_surround(x,y,xs,ys,r) || check_surround(x,y,xt,yt,r)) {
                if (!check_surround(x,y,xt,yt,r)) {
                    Circle d(x,y,r,r-sqrt((x-xs)*(x-xs)+(y-ys)*(y-ys)),sqrt((x-xt)*(x-xt)+(y-yt)*(y-yt))-r,1);
                    rat_data.push_back(d);
                }
                else if (!check_surround(x,y,xs,ys,r)) {
                    Circle d(x,y,r,sqrt((x-xs)*(x-xs)+(y-ys)*(y-ys)),r-sqrt((x-xt)*(x-xt)+(y-yt)*(y-yt)),1);
                    Maki_data.push_back(d);
                }
            }
        }
        sort(rat_data.begin(), rat_data.end(), compare_rat);
        sort(Maki_data.begin(), Maki_data.end(), compare_Maki);
        for (int i=0; i<rat_data.size(); ++i) {
            for (int j=0; j<i; ++j) {
                if (!check_cross(rat_data[i].x,rat_data[i].y,rat_data[i].r,rat_data[j].x,rat_data[j].y,rat_data[j].r)) {
                    if (rat_data[i].include <= rat_data[j].include) rat_data[i].include = rat_data[j].include+1;
                }
            }
        }
        for (int i=0; i<Maki_data.size(); ++i) {
            for (int j=0; j<i; ++j) {
                if (!check_cross(Maki_data[i].x,Maki_data[i].y,Maki_data[i].r,Maki_data[j].x,Maki_data[j].y,Maki_data[j].r)) {
                    if (Maki_data[i].include <= Maki_data[j].include) Maki_data[i].include = Maki_data[j].include+1;
                }
            }
        }
        int max = 0;
        if (rat_data.size() == 0) {
            if (Maki_data.size() == 0) {
                max = 0;
            } else {
                for (int i=0; i<Maki_data.size(); ++i) {
                    if (max < Maki_data[i].include)
                        max = Maki_data[i].include;
                }
            }
        } else {
            if (Maki_data.size() == 0) {
                for (int i=0; i<rat_data.size(); ++i) {
                    if (max < rat_data[i].include)
                        max = rat_data[i].include;
                }
            } else {
                for (int i=0; i<rat_data.size(); ++i) {
                    if (max < rat_data[i].include)
                        max = rat_data[i].include;
                }
                for (int i=0; i<Maki_data.size(); ++i) {
                    if (max < Maki_data[i].include)
                        max = Maki_data[i].include;
                }
                for (int i=0; i<rat_data.size(); ++i) {
                    for (int j=0; j<Maki_data.size(); ++j) {
                        if (!check_cross(rat_data[i].x,rat_data[i].y,rat_data[i].r,Maki_data[j].x,Maki_data[j].y,Maki_data[j].r)) {
                            if (max < (rat_data[i].include + Maki_data[j].include))
                                max = rat_data[i].include + Maki_data[j].include;
                        }
                    }
                }
            }
        }
        cout << max << endl;
    }
}
accuracy: 1
time_ms: 10
memory_kb: 3428
final_rank: 7

code_snippet: #include <algorithm>
#include <complex>
#include <iostream>
#include <vector>
using namespace std;
using xy_t = complex<double>;
const double EPS = 1e-10;
int n;
xy_t s, t;

struct Circle {
    xy_t c;
    double r;
    Circle() {}
    Circle(double x, double y, double _r)
    : c{x, y}, r(_r) {}
    bool in_circle(const xy_t &p) const {
        return abs(p - c) + EPS <= r;
    }
    bool in_circle(const Circle &other) const {
        return abs(other.c - c) + other.r + EPS <= r;
    }
};

vector<int> can_include_circles(const vector<Circle> &crc) {
    vector<int> dp(crc.size());
    for(size_t i = 0; i < crc.size(); i++) {
        dp[i] = 1;
        for(size_t j = 0; j < i; j++) {
            if(crc[i].in_circle(crc[j]) && dp[j] + 1 > dp[i])  {
                dp[i] = dp[j] + 1;
            }
        }
    }
    return dp;
}

bool corss(const Circle &x, const Circle &y) {
    return x.r + y.r + EPS >= abs(x.c - y.c) && abs(x.r - y.r) <= abs(x.c - y.c) + EPS;
}

int solve() {
    {
        double sx, sy, tx, ty;
        cin >> sx >> sy >> tx >> ty;
        s = {sx, sy};
        t = {tx, ty};
    }
    vector<Circle> crcS, crcT;
    for(int i = 0; i < n; i++) {
        double x, y, r;
        cin >> x >> y >> r;
        Circle crc = {x, y, r};
        if(crc.in_circle(s)) {
            if(!crc.in_circle(t)) {
                crcS.push_back(crc);
            }
        } else {
            if(crc.in_circle(t)) {
                crcT.push_back(crc);
            }
        }
    }
    auto comp = [](Circle &x, Circle &y) {
        return x.r < y.r;
    };
    sort(begin(crcS), end(crcS), comp);
    sort(begin(crcT), end(crcT), comp);
    vector<int> dpS = can_include_circles(crcS),
                dpT = can_include_circles(crcT);
    int ans = 0;
    if(!dpS.empty()) ans = max(ans, *max_element(begin(dpS), end(dpS)));
    if(!dpT.empty()) ans = max(ans, *max_element(begin(dpT), end(dpT)));

    for(size_t i = 0; i < crcS.size(); i++) {
        for(size_t j = 0; j < crcT.size(); j++) {
            if(!corss(crcS[i], crcT[j])) {
                ans = max(ans, dpS[i] + dpT[j]);
            }
        }
    }
    return ans;
}

int main() {
    vector<int> ans;
    while(1) {
        cin >> n;
        if(n == 0) break;
        ans.push_back(solve());
    }
    for(const auto &i : ans) cout << i << endl;
}
accuracy: 1
time_ms: 60
memory_kb: 3604
final_rank: 12

code_snippet: #pragma GCC optimize("Ofast")
#include <iostream>
#include <vector>
#include <algorithm>
#include <map>
#include <queue>
#include <cstdio>
#include <ctime>
#include <assert.h>
#include <chrono>
#include <random>
#include <numeric>
#include <set>
#include <deque>
#include <stack>
#include <sstream>
#include <utility>
#include <cstring>
#include <unordered_map>
#include <unordered_set>
#include <tuple>
#include <array>
#include <bitset>
using namespace std;
typedef long long int ll;
typedef unsigned long long ull;

mt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count());
ll myRand(ll B) {
    return (ull)rng() % B;
}
inline double time() {
    return static_cast<double>(chrono::duration_cast<chrono::nanoseconds>(chrono::steady_clock::now().time_since_epoch()).count()) * 1e-9;
}

int main(){
    cin.tie(nullptr);
    ios::sync_with_stdio(false);
    int n;
    while(cin >> n,n){
        int sx,sy,tx,ty; cin >> sx >> sy >> tx >> ty;
        vector<int> vx,vy,vr;
        vector<int> va,vb;
        for(int i=0;i<n;i++){
            int x,y,r; cin >> x >> y >> r;
            bool f1 = ((x-sx)*(x-sx) + (y-sy)*(y-sy) < r*r);
            bool f2 = ((x-tx)*(x-tx) + (y-ty)*(y-ty) < r*r);
            if(f1 and !f2){
                int j = vx.size();
                va.push_back(j);
                vx.push_back(x);
                vy.push_back(y);
                vr.push_back(r);
            }
            else if(!f1 and f2){
                int j = vx.size();
                vb.push_back(j);
                vx.push_back(x);
                vy.push_back(y);
                vr.push_back(r);
            }
        }
        int m = vx.size();
        int m1 = va.size();
        int m2 = vb.size();
        vector<vector<int>> g(m);
        {
            for(int i:va){
                for(int j:va){
                    if(vr[i]<=vr[j])continue;
                    // i->j
                    double d = sqrt((vx[i]-vx[j])*(vx[i]-vx[j]) + (vy[i]-vy[j])*(vy[i]-vy[j]));
                    if(d < vr[i] - vr[j] - 1e-8){
                        g[i].push_back(j);
                    }
                }
            }
        }
        {
            for(int i:vb){
                for(int j:vb){
                    if(vr[i]<=vr[j])continue;
                    // i->j
                    double d = sqrt((vx[i]-vx[j])*(vx[i]-vx[j]) + (vy[i]-vy[j])*(vy[i]-vy[j]));
                    if(d < vr[i] - vr[j] - 1e-8){
                        g[i].push_back(j);
                    }
                }
            }
        }
        vector<int> dp(n,-1);
        auto dfs=[&](auto self,int s)->int{
            if(dp[s] != -1)return dp[s];
            int res = 0;
            for(int t:g[s]){
                res = max(res, self(self, t));
            }
            dp[s] = res+1;
            return res+1;
        };
        for(int i=0;i<m;i++){
            if(dp[i] == -1){
                dp[i] = dfs(dfs,i);
            }
        }
        int res = 0;
        for(int i=0;i<m;i++){
            res = max(res, dp[i]);
        }
        for(int i:va){
            for(int j:vb){
                double d = sqrt((vx[i]-vx[j])*(vx[i]-vx[j]) + (vy[i]-vy[j])*(vy[i]-vy[j]));
                if(d > vr[i] + vr[j] + 1e-8){
                    res = max(res, dp[i]+dp[j]);
                }
            }
        }
        cout << res << "\n";
    }
}
accuracy: 1
time_ms: 40
memory_kb: 5984
final_rank: 16

code_snippet: #include<bits/stdc++.h> 
using namespace std;
typedef long long ll;
#define all(x) (x).begin(),(x).end()
template<typename T1,typename T2> bool chmin(T1 &a,T2 b){if(a<=b)return 0; a=b; return 1;}
template<typename T1,typename T2> bool chmax(T1 &a,T2 b){if(a>=b)return 0; a=b; return 1;}
int dx[4]={0,1,0,-1}, dy[4]={1,0,-1,0};
long double eps = 1e-9;
long double pi = acos(-1);

/*
正規版
メモ
norm(P) Pの絶対値の2乗 abs(P)の2乗
abs(P) Pの絶対値
arg(P)の戻り値の範囲は[-π, π]
polar(長さ,角度(ラジアン))でPointができる
int(-2.2+0.5)=-1
*/

// #include <bits/stdc++.h>
// using namespace std;
// template<class T,class U>constexpr bool chmin(T&a,const U b){if(a<=b)return false;a=b;return true;}
// template<class T,class U>constexpr bool chmax(T&a,const U b){if(a>=b)return false;a=b;return true;}
// template<class T,class U>constexpr bool bitUP(const T n,const U k){return (n>>k)&1;}



////////////////////////////
// マクロや型
////////////////////////////

using DD=long double;

const DD EPS=1e-9;
const DD INF=1e50;
const DD PI=acosl(-1.0);
#define EQ(a,b) (abs( (a) - (b) )<EPS) //a==b
#define LS(a,b) ( (a)+EPS<(b) ) //a<b
#define GR(a,b) ( (a)>(b)+EPS ) //a>b
#define LE(a,b) ( (a)<(b)+EPS ) //a<=b
#define GE(a,b) ( (a)>(b)-EPS ) //a>=b

#define X real()
#define Y imag()


//点
using Point=complex<DD>;
istream &operator>>(istream &is, Point &p) {
  DD x,y;
  is>>x>>y;
  p=Point(x,y);
  return is;
}

//点a→点bの線分
//aとbが等しい時、色々バグるから注意!
struct Segment{
    Point a,b;
    Segment()=default;
    Segment(Point a,Point b) :a(a),b(b){}
    Segment(DD ax,DD ay,DD bx,DD by):a(ax,ay),b(bx,by){}
    Segment(DD r,Point a) :a(a),b(a+polar((DD)1.0,r)){} 
};
using Line=Segment;

//円
struct Circle{
    Point p;
    DD r;
    Circle()=default;
    Circle(Point p,DD r):p(p),r(r){}
};



////////////////////////////
// 基本計算
////////////////////////////

//度→ラジアン
inline DD torad(const DD deg){return deg*PI/180;}
//ラジアン→度
inline DD todeg(const DD rad){return rad*180/PI;}
//内積 |a||b|cosθ
inline DD dot(const Point &a,const Point &b){return (conj(a)*b).X;}
//外積 |a||b|sinθ
inline DD cross(const Point &a,const Point &b){return (conj(a)*b).Y;}
//ベクトルpを反時計回りにtheta(ラジアン)回転
Point rotate(const Point &p,const DD theta){return p*Point(cos(theta),sin(theta));}

//余弦定理 cos(角度abc(ラジアン))を返す
//長さの対応に注意 ab:辺abの長さ
//verify:https://codeforces.com/gym/102056/problem/F
DD cosine_formula(const DD ab,const DD bc,const DD ca){
    return (ab*ab+bc*bc-ca*ca)/(2*ab*bc);
}

inline bool xy_sort(const Point &a,const Point &b){
    if(a.X+EPS<b.X) return true;
    if(EQ(a.X,b.X) && a.Y+EPS<b.Y) return true;
    return false;
}
inline bool yx_sort(const Point &a,const Point &b){
    if(a.Y+EPS<b.Y) return true;
    if(EQ(a.Y,b.Y) && a.X+EPS<b.X) return true;
    return false;
}


////////////////////////////
// 平行や直交
////////////////////////////

bool isOrthogonal(const Point &a,const Point &b){
    return EQ(dot(a,b),0.0);
}
//verify:http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_2_A
bool isOrthogonal(const Segment &s,const Segment &t){
    return EQ(dot(s.a-s.b,t.a-t.b),0.0);
}
bool isParallel(const Point &a,const Point &b){
    return EQ(cross(a,b),0.0);
}
//verify:http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_2_A
bool isParallel(const Segment &s,const Segment &t){
    return EQ(cross(s.a-s.b,t.a-t.b),0);
}
//線分a→bに対して点cがどの位置にあるか
//反時計回り:1　時計回り:-1 直線上(a,b,c:-2 a,c,b:0 c,a,b:2)
//verify:http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_1_C
//線分a→bの端点にcがあるなら0と判定されるはず
int ccw(const Point &a,Point b,Point c){
    if(EQ(abs(b-c),0) or EQ(abs(a-c),0)) return 0;
    b-=a;c-=a;
    if(cross(b,c)>EPS) return 1;
    if(cross(b,c)<-EPS) return -1;
    if(dot(b,c)<-EPS) return 2;
    if(LS(norm(b),norm(c))) return -2;
    return 0;
}

////////////////////////////
// 射影と反射
////////////////////////////

//射影
//直線lに点pから垂線を引いたときの交点
//verify:http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_1_A
Point project(const Point &p,const Line &l){
    Point base=l.b-l.a;
    DD r=dot(p-l.a,base)/norm(base);
    return l.a+base*r;
}
//反射
//直線lに対して点pと対称な点
//verify:http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_1_B
Point reflect(const Point &p,const Line &l){
    return p+(project(p,l)-p)*(DD)2.0;
}

////////////////////////////
// 点との距離
////////////////////////////

//点と直線の距離
DD DistPL(const Point &p,const Line &l){
    return abs(cross(l.b-l.a,p-l.a))/abs(l.b-l.a);
}
//点と線分の距離
DD DistPS(const Point &p,const Segment &s){
    if( dot(s.b-s.a,p-s.a)<0.0 ) return abs(p-s.a);
    if( dot(s.a-s.b,p-s.b)<0.0 ) return abs(p-s.b);
    return DistPL(p,s);
}

////////////////////////////
// 円
////////////////////////////
//直線lと円Cの交点
//l.aにより近い方がindexが小さい
//veirfy:http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_7_D
vector<Point> crossPointLC(const Line &l,const Circle &c){
    vector<Point> ret;
    if(GR(DistPL(c.p,l),c.r)) return ret; //交点がないとき、空ベクトルを返す
    Point pr=project(c.p,l);
    Point e=(l.b-l.a)/(abs(l.b-l.a));
    DD base=sqrt(c.r*c.r-norm(pr-c.p));
    ret.push_back(pr-e*base);
    ret.push_back(pr+e*base);
    if(EQ(DistPL(c.p,l),c.r)) ret.pop_back(); //接するとき
    return ret;
}
//線分sと円cの交点
//交点がないときは空ベクトルを返す
//線分の端が交わる場合も交点とみなす
//s.aにより近い方がindexが小さい
vector<Point> crossPointSC(const Segment &s,const Circle &c){
    vector<Point> ret;
    if(DistPS(c.p,s)>c.r+EPS) return ret;
    auto koho=crossPointLC(s,c);
    for(auto p:koho){
        if(ccw(s.a,s.b,p)==0 or EQ(abs(p-s.a),0) or EQ(abs(p-s.b),0)) ret.push_back(p);
    }
    return ret;
}

//円aと円bの共通接線の数
//離れている:4 外接:3 交わる:2 内接:1 内包:0
//verify:http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_7_A
int intersect(const Circle &a,const Circle &b){
    DD d=abs(a.p-b.p);
    if(GR(d,a.r+b.r)) return 4;
    if(EQ(d,a.r+b.r)) return 3;
    if(EQ(d,abs(a.r-b.r))) return 1;
    if(LS(d,abs(a.r-b.r))) return 0;
    return 2;
}

//円aと円bの交点
//交点がないときは空ベクトルを返す
//verify:http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_7_E
vector<Point> crossPoint(const Circle &a,const Circle &b){
    vector<Point> ret;
    if(GR(abs(a.p - b.p), a.r + b.r)) return ret;
    if(GR(max(a.r, b.r), abs(a.p - b.p) + min(a.r, b.r))) return ret;
    DD d=abs(a.p-b.p);
    DD s=acosl((a.r*a.r+d*d-b.r*b.r)/(2*a.r*d)); //0~π
    DD t=arg(b.p-a.p);
    if(EQ(a.r+b.r,d)) ret.push_back(a.p+polar(a.r,t));
    else ret.push_back(a.p+polar(a.r,t+s)),ret.push_back(a.p+polar(a.r,t-s));
    return ret;
}


int n;
vector<Circle> c;
vector<int> f(vector<pair<DD,int>> &v){
    vector<int> ret(n);
    for(int i=0;i<(int)v.size();i++){
        int idx = v[i].second;
        ret[idx] = 1;
        for(int j=0;j<i;j++){
            int idy = v[j].second;
            if(crossPoint(c[idx],c[idy]).empty()){
                chmax(ret[idx], ret[idy] + 1);
            }
        }
    }
    return ret;
}

signed main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout << fixed << setprecision(20);

    while(cin>>n, n){
        Point s,t;
        cin>>s>>t;
        c.resize(n);
        vector<pair<DD, int>> l,r;
        for(int i=0;i<n;i++){
            Point p;
            DD rr;
            cin>>p>>rr;
            c[i] = Circle(p, rr);
            if(LS(abs(p-s), rr) and LS(abs(p-t), rr)) continue;
            if(LS(abs(p-s), rr)) l.push_back({rr, i});
            if(LS(abs(p-t), rr)) r.push_back({rr, i});
        }
        sort(all(l));
        sort(all(r));
        vector<int> a1 = f(l);
        vector<int> a2 = f(r);
        int ans = 0;
        for(auto i:a1)chmax(ans, i);
        for(auto i:a2)chmax(ans, i);
        for(auto [d, i]:l){
            for(auto [d2, j]:r){
                assert(i != j);
                if(crossPoint(c[i], c[j]).empty()){
                    chmax(ans, a1[i] + a2[j]);
                }
            }
        }
        cout << ans << "\n";
    }
}
accuracy: 1
time_ms: 850
memory_kb: 3936
final_rank: 17

code_snippet: #pragma GCC ta g("avx2")
#pragma GCC optimize("Ofast")
#pragma GCC optimize("unroll-loops")
#include <bits/stdc++.h>
using namespace std;
#define DEBUG
#ifdef DEBUG
template <class T, class U>
ostream &operator<<(ostream &os, const pair<T, U> &p) {
    os << '(' << p.first << ',' << p.second << ')';
    return os;
}
template <class T> ostream &operator<<(ostream &os, const vector<T> &v) {
    os << '{';
    for(int i = 0; i < (int)v.size(); i++) {
        if(i) { os << ','; }
        os << v[i];
    }
    os << '}';
    return os;
}
void debugg() { cerr << endl; }
template <class T, class... Args>
void debugg(const T &x, const Args &... args) {
    cerr << " " << x;
    debugg(args...);
}
#define debug(...)                                                             \
    cerr << __LINE__ << " [" << #__VA_ARGS__ << "]: ", debugg(__VA_ARGS__)
#define dump(x) cerr << __LINE__ << " " << #x << " = " << (x) << endl
#else
#define debug(...) (void(0))
#define dump(x) (void(0))
#endif
using namespace std;
typedef long long ll;
typedef vector<ll> vl;
typedef vector<vl> vvl;
typedef vector<char> vc;
typedef vector<string> vs;
typedef vector<bool> vb;
typedef vector<double> vd;
typedef pair<ll,ll> P;
typedef pair<int,int> pii;
typedef vector<P> vpl;
typedef tuple<ll,ll,ll> tapu;
#define rep(i,n) for(int i=0; i<(n); i++)
#define REP(i,a,b) for(int i=(a); i<(b); i++)
#define all(x) (x).begin(), (x).end()
#define rall(x) (x).rbegin(), (x).rend()
const int inf = (1<<30)-1;
const ll linf = 1LL<<61;
const int MAX = 510000;
int dy[8] = {0,1,0,-1,1,-1,-1,1};
int dx[8] = {-1,0,1,0,1,-1,1,-1};
const double pi = acos(-1);
const double eps = 1e-7;
template<typename T1,typename T2> inline bool chmin(T1 &a,T2 b){
	if(a>b){
		a = b; return true;
	}
	else return false;
}
template<typename T1,typename T2> inline bool chmax(T1 &a,T2 b){
	if(a<b){
		a = b; return true;
	}
	else return false;
}
template<typename T> inline void print(T &a){
    int sz = a.size();
    for(auto itr = a.begin(); itr != a.end(); itr++){
		cout << *itr;
        sz--;
        if(sz) cout << " ";
	}
    cout << "\n";
}
template<typename T1,typename T2> inline void print2(T1 a, T2 b){
	cout << a << " " << b << "\n";
}
template<typename T1,typename T2,typename T3> inline void print3(T1 a, T2 b, T3 c){
	cout << a << " " << b << " " << c << "\n";
}
void mark() {cout << "#" << "\n";}
ll pcount(ll x) {return __builtin_popcountll(x);}
//#include <atcoder/maxflow>
//using namespace atcoder;
//const int mod = 1e9 + 7;
const int mod = 998244353;

struct circle{
    int x,y,r;
    circle() {}
    circle(int x, int y, int r) : x(x), y(y), r(r) {}
    bool operator< (const circle &c) const {
        return x-r < c.x-c.r;
    }
};

int main(){
    while(1){
        int n; cin >> n;
        if(!n) break;
        int a,b,c,d; cin >> a >> b >> c >> d;
        vector<circle> v(n);
        rep(i,n){
            cin >> v[i].x >> v[i].y >> v[i].r;
        }
        sort(rall(v));
        auto intersect = [&](circle c, circle d) -> bool {
            ll dist = abs(c.x-d.x) * abs(c.x-d.x) + abs(c.y-d.y) * abs(c.y-d.y);
            ll rm = max(c.r,d.r) - min(c.r,d.r);
            ll rM = c.r+d.r;
            return rm*rm <= dist && dist <= rM*rM;
        };
        auto contain = [&](circle c, int x, int y) -> bool {
            ll dist = abs(c.x-x) * abs(c.x-x) + abs(c.y-y) * abs(c.y-y);
            return c.r*c.r >= dist;
        };
        vector<circle> S,T;
        rep(i,n){
            if(contain(v[i],a,b)){
                if(!contain(v[i],c,d)) S.emplace_back(v[i]);
            }else{
                if(contain(v[i],c,d)) T.emplace_back(v[i]);
            }
        }
        int ssize = S.size(), tsize = T.size();
        vector<int> sp(ssize,1), tp(tsize,1);
        rep(i,ssize){
            rep(j,i){
                if(!intersect(S[j],S[i])) chmax(sp[i],sp[j]+1);
            }
        }
        rep(i,tsize){
            rep(j,i){
                if(!intersect(T[j],T[i])) chmax(tp[i],tp[j]+1);
            }
        }
        int ans = 0;
        rep(i,ssize) rep(j,tsize){
            if(!intersect(S[i],T[j])) chmax(ans, sp[i]+tp[j]);
        }
        rep(i,ssize) chmax(ans, sp[i]);
        rep(j,tsize) chmax(ans, tp[j]);
        cout << ans << endl;
    }
}
accuracy: 1
time_ms: 20
memory_kb: 3312
final_rank: 5

code_snippet: #include <bits/stdc++.h>
using namespace std;

//geometry library by maine

//basic
using Real = double;
using Point = complex<Real>;
#define x real()
#define y imag()
const Real EPS = 1e-8, PI = acos(-1), INF = 1e10;

istream& operator>>(istream& is, Point& p) {
    Real a, b;
    is >> a >> b;
    p = Point(a, b);
    return is;
}
ostream& operator<<(ostream& os, Point p) {
    return os << fixed << setprecision(10) << p.x << " " << p.y;
}

Point operator*(const Point& p, const Real& d) { return Point(p.x * d, p.y * d); }

bool eq(const Real& r, const Real& s) { return abs(r - s) < EPS; }
bool eq(const Point& p, const Point& q) { return abs(p - q) < EPS; }

namespace std {
bool operator<(const Point& a, const Point& b) {
    return !eq(a.x, b.x) ? a.x < b.x : a.y < b.y;
}
}  // namespace std

Real get_angle(const Point& a, const Point& b, const Point& c) {
    return arg((c - a) / (b - a));
}

inline int inc(int i, int N) {
    return (i == N - 1 ? 0 : i + 1);
}
inline int dec(int i, int N) {
    return (i == 0 ? N - 1 : i - 1);
}

//unit vector
Point e(const Point& p) { return p / abs(p); }

//angle transformation
Real radian_to_degree(Real r) { return r * 180.0 / PI; }
Real degree_to_radian(Real d) { return d * PI / 180.0; }

//basic functions
Real dot(const Point& p, const Point& q) { return p.x * q.x + p.y * q.y; }
Real cross(const Point& p, const Point& q) { return p.x * q.y - p.y * q.x; }
Point rotate(const Real& theta, const Point& p) {
    return {cos(theta) * p.x - sin(theta) * p.y, sin(theta) * p.x + cos(theta) * p.y};
}
Point rotate90(const Point& p) {
    return {-p.y, p.x};
}

//structs : Line, Segment, Circle
struct Line {
    Point a, b;
    Line() = default;
    Line(Point a, Point b) : a(a), b(b) {}
    Point d() const { return e(b - a); }  //direction vector
    Point n() const {
        Point dd = d();
        return {dd.y, -dd.x};
    }  //normal vector
};
struct Segment : Line {
    Segment() = default;
    Segment(Point a, Point b) : Line(a, b) {}
};
struct Circle {
    Point p;
    Real r;
    Circle() = default;
    Circle(Point p, Real r) : p(p), r(r){};
};
using Points = vector<Point>;
using Polygon = vector<Point>;
using Polygons = vector<Polygon>;
using Lines = vector<Line>;
using Segments = vector<Segment>;
using Circles = vector<Circle>;

//happy functions
//https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_1_C
int ccw(const Point& a, const Point& bb, const Point& cc) {
    Point b = bb - a, c = cc - a;
    if (cross(b, c) > EPS)
        return 1;  //COUNTER_CLOCKWISE
    if (cross(b, c) < -EPS)
        return -1;  //CLOCKWISE
    if (dot(b, c) < 0)
        return 2;  //ONLINE_BACK  c-a-b
    if (norm(b) < norm(c))
        return -2;  //ONLINE_FRONT a-b-c
    return 0;       //ON_SEGMENT   a-c-b
}

bool parallel(const Line& l, const Line& m) { return eq(cross(l.d(), m.d()), 0.0); }
bool orthogonal(const Line& l, const Line& m) { return eq(dot(l.d(), m.d()), 0.0); }
Point projection(const Line& l, const Point& p) { return l.a + (l.a - l.b) * (dot(p - l.a, l.a - l.b) / norm(l.a - l.b)); }
Point reflection(const Line& l, const Point& p) { return p + (projection(l, p) - p) * 2.0; }

//intersect
bool intersect(const Line& l, const Point& p) { return abs(ccw(l.a, l.b, p)) != 1; }
bool intersect(const Line& l, const Line& m) { return !parallel(l, m) || (parallel(l, m) && intersect(l, m.a)); }
bool intersect(const Segment& s, const Point& p) { return ccw(s.a, s.b, p) == 0; }
bool intersect(const Line& l, const Segment& s) { return cross(l.d(), s.a - l.a) * cross(l.d(), s.b - l.a) < EPS; }
bool intersect(const Segment& s, const Segment& t) {
    return ccw(s.a, s.b, t.a) * ccw(s.a, s.b, t.b) <= 0 && ccw(t.a, t.b, s.a) * ccw(t.a, t.b, s.b) <= 0;
}
bool intersect_onsegment(const Segment& s, const Point& p) { return intersect(s, p) && !eq(s.a, p) && !eq(s.b, p); }

//distance
Real distance(const Point& p, const Point& q) { return abs(p - q); }
Real distance(const Line& l, const Point& p) { return distance(p, projection(l, p)); }
Real distance(const Line& l, const Line& m) { return intersect(l, m) ? 0 : distance(l, m.a); }
Real distance(const Segment& s, const Point& p) {
    Point q = projection(s, p);
    return intersect(s, q) ? distance(p, q) : min(distance(s.a, p), distance(s.b, p));
}
Real distance(const Segment& s, const Segment& t) { return intersect(s, t) ? 0 : min({distance(s, t.a), distance(s, t.b), distance(t, s.a), distance(t, s.b)}); }
Real distance(const Line& l, const Segment& s) { return intersect(l, s) ? 0 : min(distance(l, s.a), distance(l, s.b)); }

//intersect circle
bool intersect(const Circle& c, const Point& p) { return eq(distance(c.p, p), c.r); }
bool intersect(const Circle& c, const Line& l) { return distance(l, c.p) <= c.r + EPS; }
int intersect(const Circle& c, const Segment& s) {
    if (!intersect(c, Line(s)))
        return 0;
    Real da = distance(c.p, s.a), db = distance(c.p, s.b);
    if (da < c.r + EPS && db < c.r + EPS)
        return 0;
    if (da > db)
        swap(da, db);
    if (da < c.r - EPS && db > c.r + EPS)
        return 1;
    if (intersect(s, projection(s, c.p)))
        return 2;
    return 0;
}
int intersect(Circle c1, Circle c2) {
    if (c1.r < c2.r)
        swap(c1, c2);
    Real d = distance(c1.p, c2.p);
    if (c1.r + c2.r < d)
        return 4;
    if (eq(c1.r + c2.r, d))
        return 3;
    if (c1.r - c2.r < d)
        return 2;
    if (eq(c1.r - c2.r, d))
        return 1;
    return 0;
}

//crosspoint
Point crosspoint(const Line& l, const Line& m) {
    Real A = cross(l.b - l.a, m.b - m.a);
    Real B = cross(l.b - l.a, l.b - m.a);
    if (eq(abs(A), 0.0) && eq(abs(B), 0.0))
        return m.a;
    return m.a + (m.b - m.a) * B / A;
}
Point crosspoint(const Segment& s, const Segment& t) { return crosspoint(Line(s), Line(t)); }
pair<Point, Point> crosspoint(const Circle& c, const Line& l) {
    Point p = projection(l, c.p);
    if (eq(distance(l, c.p), c.r))
        return {p, p};
    Real len = sqrt(c.r * c.r - norm(p - c.p));
    return {p - len * l.d(), p + len * l.d()};
}
pair<Point, Point> crosspoint(const Circle& c, const Segment& s) {
    Line l(s);
    if (intersect(c, s) == 2)
        return crosspoint(c, l);
    auto ret = crosspoint(c, l);
    if (dot(s.a - ret.first, s.b - ret.first) < 0)
        ret.second = ret.first;
    else
        ret.first = ret.second;
    return ret;
}
pair<Point, Point> crosspoint(const Circle& c1, const Circle& c2) {
    Real d = distance(c1.p, c2.p);
    Real a = acos((c1.r * c1.r + d * d - c2.r * c2.r) / (2 * c1.r * d));
    Real t = atan2(c2.p.y - c1.p.y, c2.p.x - c1.p.x);
    Point p1 = c1.p + Point(cos(t + a) * c1.r, sin(t + a) * c1.r);
    Point p2 = c1.p + Point(cos(t - a) * c1.r, sin(t - a) * c1.r);
    return {p1, p2};
}

//tangent
pair<Point, Point> tangent(const Circle& c, const Point& p) {
    return crosspoint(c, Circle(p, sqrt(norm(c.p - p) - c.r * c.r)));
}
Lines tangent(Circle c1, Circle c2) {
    Lines ret;
    if (c1.r < c2.r)
        swap(c1, c2);
    if (eq(c1.p, c2.p))
        return ret;
    Real g = norm(c1.p - c2.p);
    Point u = (c2.p - c1.p) / sqrt(g);
    Point v = rotate(PI / 2, u);
    for (int s : {-1, 1}) {
        Real h = (c1.r + s * c2.r) / sqrt(g);
        if (eq(1 - h * h, 0)) {
            ret.emplace_back(c1.p + u * c1.r, c1.p + (u + v) * c1.r);
        } else if (1 - h * h > 0) {
            Point uu = u * h, vv = v * sqrt(1 - h * h);
            ret.emplace_back(c1.p + (uu + vv) * c1.r, c2.p - (uu + vv) * c2.r * s);
            ret.emplace_back(c1.p + (uu - vv) * c1.r, c2.p - (uu - vv) * c2.r * s);
        }
    }
    return ret;
}

//convex
//https://onlinejudge.u-aizu.ac.jp/courses/library/4/CGL/3/CGL_3_B
bool is_convex(const Polygon& P) {
    int N = (int)P.size();
    for (int i = 0; i < N; i++) {
        if (ccw(P[i], P[(i + 1) % N], P[(i + 2) % N]) == -1)
            return false;
    }
    return true;
}
//https://onlinejudge.u-aizu.ac.jp/courses/library/4/CGL/4/CGL_4_A
Polygon convex_hull(Points P) {
    int N = (int)P.size(), k = 0;
    if (N <= 2)
        return P;
    sort(begin(P), end(P));
    Points ret(2 * N);
    for (int i = 0; i < N; ret[k++] = P[i++]) {
        while (k >= 2 && cross(ret[k - 1] - ret[k - 2], P[i] - ret[k - 1]) < EPS)
            --k;
    }
    for (int i = N - 2, t = k + 1; i >= 0; ret[k++] = P[i--]) {
        while (k >= t && cross(ret[k - 1] - ret[k - 2], P[i] - ret[k - 1]) < EPS)
            --k;
    }
    ret.resize(k - 1);
    return ret;
}
//https://onlinejudge.u-aizu.ac.jp/courses/library/4/CGL/4/CGL_4_B
Real convex_diameter(const Polygon& P) {
    int N = (int)P.size();
    int is = 0, js = 0;
    for (int i = 1; i < N; i++) {
        if (P[i].y < P[is].y)
            is = i;
        if (P[i].y > P[js].y)
            js = i;
    }
    Real maxdist = norm(P[is] - P[js]);
    int maxi, maxj, i, j;
    maxi = i = is;
    maxj = j = js;
    do {
        if (cross(P[inc(i, N)] - P[i], P[inc(j, N)] - P[j]) >= 0)
            j = inc(j, N);
        else
            i = inc(i, N);
        if (norm(P[i] - P[j]) > maxdist) {
            maxdist = norm(P[i] - P[j]);
            maxi = i;
            maxj = j;
        }
    } while (i != is || j != js);
    maxi = maxi;
    maxj = maxj;
    return sqrt(maxdist);
}
//https://onlinejudge.u-aizu.ac.jp/courses/library/4/CGL/4/CGL_4_C
Polygon convex_cut(const Polygon& P, const Line& l) {
    Polygon ret;
    int N = (int)P.size();
    for (int i = 0; i < N; i++) {
        Point now = P[i], nxt = P[(inc(i, N))];
        if (ccw(l.a, l.b, now) != -1)
            ret.emplace_back(now);
        if (ccw(l.a, l.b, now) * ccw(l.a, l.b, nxt) == -1)
            ret.emplace_back(crosspoint(Line(now, nxt), l));
    }
    return ret;
}

//other
enum
{
    OUT,
    ON,
    IN
};

//https://onlinejudge.u-aizu.ac.jp/courses/library/4/CGL/3/CGL_3_C
int contains(const Polygon& Q, const Point& p) {
    bool in = false;
    int N = (int)Q.size();
    for (int i = 0; i < N; i++) {
        Point a = Q[i] - p, b = Q[(i + 1) % N] - p;
        if (a.y > b.y)
            swap(a, b);
        if (a.y <= 0 && 0 < b.y && cross(a, b) < 0)
            in = !in;
        if (cross(a, b) == 0 && dot(a, b) <= 0)
            return ON;
    }
    return in ? IN : OUT;
}

//https://onlinejudge.u-aizu.ac.jp/courses/library/4/CGL/3/CGL_3_A
Real area(const Polygon& P) {
    Real A = 0;
    for (int i = 0; i < (int)P.size(); i++) {
        A += cross(P[i], P[(i + 1) % P.size()]);
    }
    return A * 0.5;
}

//https://onlinejudge.u-aizu.ac.jp/courses/library/4/CGL/7/CGL_7_H
Real cross_area(const Circle& c, const Point& a, const Point& b) {
    Point va = c.p - a, vb = c.p - b;
    Real f = cross(va, vb), ret = 0.0;
    if (eq(f, 0.0))
        return ret;
    if (max(abs(va), abs(vb)) < c.r + EPS)
        return f;
    if (distance(Segment(a, b), c.p) > c.r - EPS)
        return c.r * c.r * arg(vb * conj(va));
    auto u = crosspoint(c, Segment(a, b));
    vector<Point> V{a, u.first, u.second, b};
    for (int i = 0; i < (int)V.size() - 1; i++) {
        ret += cross_area(c, V[i], V[i + 1]);
    }
    return ret;
}
Real area(const Polygon& p, const Circle& c) {
    int N = (int)p.size();
    if (N < 3)
        return 0.0;
    Real ret = 0;
    for (int i = 0; i < N; i++) {
        ret += cross_area(c, p[i], p[inc(i, N)]);
    }
    return ret / 2.0;
}

//https://onlinejudge.u-aizu.ac.jp/problems/CGL_5_A
Real closest_pair(Points& P, int left, int right) {
    if (right - left <= 1)
        return 1e18;
    int mid = (left + right) / 2;
    Real xx = P[mid].x;
    Real dist = min(closest_pair(P, left, mid), closest_pair(P, mid, right));
    inplace_merge(P.begin() + left, P.begin() + mid, P.begin() + right, [&](const Point& a, const Point& b) { return a.y < b.y; });
    Points memo;
    memo.reserve(right - left);
    for (int i = left; i < right; i++) {
        if (abs(P[i].x - xx) >= dist)
            continue;
        for (int j = (int)memo.size() - 1; j >= 0; j--) {
            if (P[i].y - memo[j].y >= dist)
                break;
            dist = min(dist, distance(P[i], memo[j]));
        }
        memo.emplace_back(P[i]);
    }
    return dist;
}
Real closest_pair(Points P) {
    sort(begin(P), end(P));
    return closest_pair(P, 0, (int)P.size());
}

//https://onlinejudge.u-aizu.ac.jp/courses/library/4/CGL/7/CGL_7_B
Circle incircle(Polygon P) {
    assert((int)P.size() == 3);
    Real l0 = distance(P[1], P[2]), l1 = distance(P[0], P[2]), l2 = distance(P[0], P[1]);
    Circle c;
    c.p = crosspoint(Line(P[0], (P[1] * l1 + P[2] * l2) / (l1 + l2)), Line(P[1], (P[0] * l0 + P[2] * l2) / (l0 + l2)));
    c.r = distance(Line(P[0], P[1]), c.p);
    return c;
}

//https://onlinejudge.u-aizu.ac.jp/courses/library/4/CGL/7/CGL_7_C
Circle circumcircle(Polygon P) {
    assert((int)P.size() == 3);
    Circle c;
    c.p = crosspoint(Line((P[0] + P[1]) / 2.0, (P[0] + P[1]) / 2.0 + rotate90(P[0] - P[1])),
        Line((P[0] + P[2]) / 2.0, (P[0] + P[2]) / 2.0 + rotate90(P[0] - P[2])));
    c.r = distance(c.p, P[0]);
    return c;
}

#undef x
#undef y


int main() {
    int N;
    while (cin >> N, N) {
        Point s, t;
        cin >> s >> t;
        Circles C(N);
        for (auto&& c : C) {
            cin >> c.p >> c.r;
        }
        sort(begin(C), end(C), [](const auto& x, const auto& y) { return x.r < y.r; });
        auto maine = [&](Point p, Point q) {
            vector<int> dp(N);
            for (int i = 0; i < N; i++) {
                if (distance(p, C[i].p) < C[i].r && distance(q, C[i].p) > C[i].r) {
                    dp[i] = 1;
                    for (int j = 0; j < i; j++) {
                        if (intersect(C[i], C[j]) == 0)
                            dp[i] = max(dp[i], dp[j] + 1);
                    }
                }
            }
            return dp;
        };
        auto S = maine(s, t), T = maine(t, s);
        int ans = 0;
        for (int i = 0; i < N; i++) {
            ans = max(ans, S[i]);
            ans = max(ans, T[i]);
            for (int j = 0; j < N; j++) {
                if (intersect(C[i], C[j]) == 4)
                    ans = max(ans, S[i] + T[j]);
            }
        }
        cout << ans << endl;
    }
}
accuracy: 1
time_ms: 440
memory_kb: 3552
final_rank: 14

code_snippet: #include <bits/stdc++.h>
using namespace std;
const double EPS = 0.00000001;
struct point{
  double x, y;
  point(){
  }
  point(double x, double y): x(x), y(y){
  }
  point operator -(point P){
    return point(x - P.x, y - P.y);
  }
};
double abs(point P){
  return sqrt(P.x * P.x + P.y * P.y);
}
double dist(point P, point Q){
  return abs(Q - P);
}
int main(){
  while (true){
    int n;
    cin >> n;
    if (n == 0){
      break;
    }
    point S, T;
    cin >> S.x >> S.y >> T.x >> T.y;
    vector<tuple<double, double, double>> C1, C2;
    for (int i = 0; i < n; i++){
      double x, y, r;
      cin >> x >> y >> r;
      point P(x, y);
      double dS = dist(P, S);
      double dT = dist(P, T);
      if (dS < r && dT > r){
        C1.push_back(make_tuple(r, x, y));
      }
      if (dT < r && dS > r){
        C2.push_back(make_tuple(r, x, y));
      }
    }
    sort(C1.begin(), C1.end());
    int N = C1.size();
    vector<double> r1(N);
    vector<point> P1(N);
    for (int i = 0; i < N; i++){
      r1[i] = get<0>(C1[i]);
      P1[i].x = get<1>(C1[i]);
      P1[i].y = get<2>(C1[i]);
    }
    sort(C2.begin(), C2.end());
    int M = C2.size();
    vector<double> r2(M);
    vector<point> P2(M);
    for (int i = 0; i < M; i++){
      r2[i] = get<0>(C2[i]);
      P2[i].x = get<1>(C2[i]);
      P2[i].y = get<2>(C2[i]);
    }
    vector<int> dp1(N + 1, 0);
    for (int i = 0; i < N; i++){
      dp1[i + 1] = 1;
      for (int j = 0; j < i; j++){
        if (dist(P1[i], P1[j]) < r1[i] - r1[j] - EPS){
          dp1[i + 1] = max(dp1[i + 1], dp1[j + 1] + 1);
        }
      }
    }
    vector<int> dp2(M + 1, 0);
    for (int i = 0; i < M; i++){
      dp2[i + 1] = 1;
      for (int j = 0; j < i; j++){
        if (dist(P2[i], P2[j]) < r2[i] - r2[j] - EPS){
          dp2[i + 1] = max(dp2[i + 1], dp2[j + 1] + 1);
        }
      }
    }
    int ans = 0;
    for (int i = 0; i <= N; i++){
      ans = max(ans, dp1[i]);
    }
    for (int i = 0; i <= M; i++){
      ans = max(ans, dp2[i]);
    }
    for (int i = 0; i < N; i++){
      for (int j = 0; j < M; j++){
        if (dist(P1[i], P2[j]) > r1[i] + r2[j] + EPS){
          ans = max(ans, dp1[i + 1] + dp2[j + 1]);
        }
      }
    }
    cout << ans << endl;
  }
}
accuracy: 1
time_ms: 30
memory_kb: 3204
final_rank: 4

code_snippet: #include "iostream"
#include "climits"
#include "list"
#include "queue"
#include "stack"
#include "set"
#include "functional"
#include "algorithm"
#include "string"
#include "map"
#include "unordered_map"
#include "unordered_set"
#include "iomanip"
#include "cmath"
#include "random"
#include "bitset"
#include "cstdio"
#include "numeric"
#include "cassert"
#include "ctime"
#include "complex"

using namespace std;

constexpr long long int MOD = 1000000007;
//constexpr int MOD = 1000000007;
//constexpr int MOD = 998244353;
//constexpr long long int MOD = 998244353;
constexpr double EPS = 1e-12;

//int N, M, K, T, H, W, L, R;
long long int N, M, K, T, H, W, L, R;

struct Circle {
	long double x, y, r;
	Circle() {
		cin >> x >> y >> r;
	}
	bool operator<(const Circle&c) const {
		return r < c.r;
	}
};

int main() {
	ios::sync_with_stdio(false);
	cin.tie(0);

	while (cin >> N, N) {
		long double sx, sy, gx, gy;
		cin >> sx >> sy >> gx >> gy;
		vector<Circle>c(N);
		sort(c.begin(), c.end());
		vector<Circle>a;
		vector<Circle>b;
		a.push_back(c[0]);
		b.push_back(c[0]);
		a[0].x = sx, a[0].y = sy, a[0].r = 0;
		b[0].x = gx, b[0].y = gy, b[0].r = 0;
		for (int i = 0; i < N; i++) {
			auto sdis = hypotl(c[i].x - sx, c[i].y - sy);
			auto gdis = hypotl(c[i].x - gx, c[i].y - gy);
			if (sdis < c[i].r&&gdis>c[i].r) {
				a.push_back(c[i]);
			}
			if (sdis > c[i].r&&gdis < c[i].r) {
				b.push_back(c[i]);
			}
		}
		vector<vector<int>>dp(a.size(), vector<int>(b.size(), -MOD));
		vector<vector<int>>aok(a.size(), vector<int>(a.size()));
		for (int i = 0; i < a.size(); i++) {
			for (int j = i + 1; j < a.size(); j++) {
				if (hypot(a[i].x - a[j].x, a[i].y - a[j].y) <= abs(a[i].r - a[j].r) - EPS) {
					aok[i][j] = 1;
				}
			}
		}
		vector<vector<int>>bok(b.size(), vector<int>(b.size()));
		for (int i = 0; i < b.size(); i++) {
			for (int j = i + 1; j < b.size(); j++) {
				if (hypot(b[i].x - b[j].x, b[i].y - b[j].y) <= abs(b[i].r - b[j].r) - EPS) {
					bok[i][j] = 1;
				}
			}
		}
		vector<vector<int>>ok(a.size(), vector<int>(b.size()));
		for (int i = 0; i < a.size(); i++) {
			for (int j = 0; j < b.size(); j++) {
				if (hypot(a[i].x - b[j].x, a[i].y - b[j].y) >= a[i].r + b[j].r + EPS) {
					ok[i][j] = 1;
				}
			}
		}
		dp[0][0] = 0;
		for (int i = 0; i < a.size(); i++) {
			for (int j = 0; j < b.size(); j++) {
				for (int k = i + 1; k < a.size(); k++) {
					if (aok[i][k] && ok[k][j]) {
						dp[k][j] = max(dp[k][j], dp[i][j] + 1);
					}
				}
				for (int k = j + 1; k < b.size(); k++) {
					if (bok[j][k] && ok[i][k]) {
						dp[i][k] = max(dp[i][k], dp[i][j] + 1);
					}
				}
			}
		}
		int ans = 0;
		for (auto i : dp)for (auto j : i)ans = max(ans, j);
		cout << ans << endl;
	}
}
accuracy: 1
time_ms: 850
memory_kb: 7304
final_rank: 19

code_snippet: #include<iostream>
#include<vector>
using namespace std;
int N;
int X[1000],Y[1000],R[1000];
bool cont(int id,int x,int y)
{
	int dx=X[id]-x,dy=Y[id]-y;
	return dx*dx+dy*dy<R[id]*R[id];
}
vector<pair<int,int> >f(int sx,int sy,int gx,int gy)
{
	vector<int>id;
	for(int i=0;i<N;i++)
	{
		if(cont(i,sx,sy)&&!cont(i,gx,gy))id.push_back(i);
	}
	int n=id.size();
	vector<pair<int,int> >E;
	for(int i=0;i<n;i++)for(int j=0;j<n;j++)if(R[id[i]]<R[id[j]])
	{
		int dx=X[id[i]]-X[id[j]],dy=Y[id[i]]-Y[id[j]];
		int dr=R[id[j]]-R[id[i]];
		if(dx*dx+dy*dy<dr*dr)E.push_back(make_pair(i,j));
	}
	vector<int>dist(n,1);
	for(int i=0;i<n;i++)
	{
		for(pair<int,int>e:E)if(dist[e.first]+1>dist[e.second])dist[e.second]=dist[e.first]+1;
	}
	vector<pair<int,int> >ret(n);
	for(int i=0;i<n;i++)ret[i]=make_pair(id[i],dist[i]);
	return ret;
}
main()
{
	while(cin>>N,N)
	{
		int sx,sy,gx,gy;
		cin>>sx>>sy>>gx>>gy;
		for(int i=0;i<N;i++)cin>>X[i]>>Y[i]>>R[i];
		vector<pair<int,int> >A=f(sx,sy,gx,gy);
		vector<pair<int,int> >B=f(gx,gy,sx,sy);
		int ans=0;
		for(pair<int,int>p:A)if(ans<p.second)ans=p.second;
		for(pair<int,int>p:B)if(ans<p.second)ans=p.second;
		for(pair<int,int>p:A)for(pair<int,int>q:B)
		{
			int dx=X[p.first]-X[q.first],dy=Y[p.first]-Y[q.first];
			int nr=R[p.first]+R[q.first];
			if(dx*dx+dy*dy<=nr*nr)continue;
			if(ans<p.second+q.second)ans=p.second+q.second;
		}
		cout<<ans<<endl;
	}
}
accuracy: 1
time_ms: 1580
memory_kb: 10696
final_rank: 20

code_snippet: #include <bits/stdc++.h>
using namespace std;
typedef long long ll;
template<class T>bool chmax(T &a, const T &b) { if (a<b) { a=b; return true; } return false; }
template<class T>bool chmin(T &a, const T &b) { if (b<a) { a=b; return true; } return false; }
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define mp make_pair
#define si(x) int(x.size())
const int mod=1000000007,MAX=1005;
const int INF=1e6;
//const ll INF=1LL<<60;

//幾何ライブラリ

const double eps=1e-8;
const double pi=acos((long double)-1.0L);
#define equals(a,b) (fabs((a)-(b))<eps)

double torad(int deg) {return (double)(deg)*pi/180.0;}
double todeg(double ang) {return ang*180.0/pi;}

class Point{
public:
    double x,y;
    
    Point(double x=0,double y=0):x(x),y(y){}
    
    Point operator + (Point p){return Point(x+p.x,y+p.y);}
    Point operator - (Point p){return Point(x-p.x,y-p.y);}
    Point operator * (double a){return Point(a*x,a*y);}
    Point operator / (double a){return Point(x/a,y/a);}
    
    double abs(){return sqrt(norm());}
    double norm(){return x*x+y*y;}
    
    bool operator < (const Point &p)const{
        return x+eps<p.x||(equals(x,p.x)&&y+eps<p.y);
    }
    
    bool operator == (const Point &p)const{
        return fabs(x-p.x)<eps&&fabs(y-p.y)<eps;
    }
};

typedef Point Vector;

double norm(Vector a){
    return a.x*a.x+a.y*a.y;
}

double abs(Vector a){
    return sqrt(norm(a));
}

double dot(Vector a,Vector b){
    return a.x*b.x+a.y*b.y;
}

double cross(Vector a,Vector b){
    return a.x*b.y-a.y*b.x;
}

struct Segment{
    Point p1,p2;
};

bool isOrthogonal(Vector a,Vector b){
    return equals(dot(a,b),0.0);
}

bool isOrthogonal(Point a1,Point a2,Point b1,Point b2){
    return isOrthogonal(a1-a2,b1-b2);
}

bool isOrthogonal(Segment s1,Segment s2){
    return equals(dot(s1.p2-s1.p1,s2.p2-s2.p1),0.0);
}

bool isParallel(Vector a,Vector b){
    return equals(cross(a,b),0.0);
}

bool isParallel(Point a1,Point a2,Point b1,Point b2){
    return isParallel(a1-a2,b1-b2);
}

bool isParallel(Segment s1,Segment s2){
    return equals(cross(s1.p2-s1.p1,s2.p2-s2.p1),0.0);
}

Point project(Segment s,Point p){
    Vector base=s.p2-s.p1;
    double r=dot(p-s.p1,base)/norm(base);
    return s.p1+base*r;
}

Point reflect(Segment s,Point p){
    return p+(project(s,p)-p)*2.0;
}

Point turn(Point p,Point c,double pi){
    double q=atan2(p.y-c.y,p.x-c.x);
    q+=pi;
    p=c+Point{cos(q)*abs(p-c),sin(q)*abs(p-c)};
    
    return p;
}
//pをcを中心としてpi回転させる(1周で2π)
//p=cのときnan

static const int counter_clockwise=1;
static const int clockwise=-1;
static const int online_back=2;
static const int online_front=-2;
static const int on_segment=0;

int ccw(Point p0,Point p1,Point p2){
    Vector a=p1-p0;
    Vector b=p2-p0;
    
    if(cross(a,b)>eps) return counter_clockwise;
    if(cross(a,b)<-eps) return clockwise;
    if(dot(a,b)<-eps) return online_back;
    if(a.norm()<b.norm()) return online_front;
    
    return on_segment;
}

bool intersect(Point p1,Point p2,Point p3,Point p4){
    return(ccw(p1,p2,p3)*ccw(p1,p2,p4)<=0&&ccw(p3,p4,p1)*ccw(p3,p4,p2)<=0);
}

bool intersect(Segment s1,Segment s2){
    return intersect(s1.p1,s1.p2,s2.p1,s2.p2);
}

bool overlap(Segment s1,Segment s2){
    int a=ccw(s1.p1,s1.p2,s2.p1),b=ccw(s1.p1,s1.p2,s2.p2);
    if(a&1||b&1) return 0;
    if(a==2){
        if(b==-2||(b==0&&!(s2.p2==s1.p1))) return 1;
        else return 0;
    }
    if(a==-2){
        if(b==2||(b==0&&!(s2.p2==s1.p2))) return 1;
        else return 0;
    }
    if(a==0){
        if(s1.p1==s2.p1){
            if(b!=2) return 1;
            else return 0;
        }
        else if(s1.p2==s2.p1){
            if(b!=-2) return 1;
            else return 0;
        }
        else return 1;
    }
    return 0;
}
//s1とs2の共通の線分(長さ0より大きい)があるかどうか

typedef Segment Line;

double getDistance(Point a,Point b){
    return abs(a-b);
}

double getDistanceLP(Line l,Point p){
    return abs(cross(l.p2-l.p1,p-l.p1)/abs(l.p2-l.p1));
}

double getDistanceSP(Segment s,Point p){
    if(dot(s.p2-s.p1,p-s.p1)<0.0) return abs(p-s.p1);
    if(dot(s.p1-s.p2,p-s.p2)<0.0) return abs(p-s.p2);
    return getDistanceLP(s,p);
}

double getDistance(Segment s1,Segment s2){
    if(intersect(s1,s2)) return 0.0;
    return min({getDistanceSP(s1,s2.p1),getDistanceSP(s1,s2.p2),getDistanceSP(s2,s1.p1),getDistanceSP(s2,s1.p2)});
}

Point getCrossPointS(Segment s1,Segment s2){
    //if(ccw(s1.p1,s1.p2,s2.p1)==0&&ccw(s1.p1,s1.p2,s2.p2)==0) return s1.p1;
    Vector base=s2.p2-s2.p1;
    double d1=abs(cross(base,s1.p1-s2.p1));
    double d2=abs(cross(base,s1.p2-s2.p1));
    double t=d1/(d1+d2);
    return s1.p1+(s1.p2-s1.p1)*t;
}//同じ時壊れます

Point getCrossPointL(Line l1,Line l2){
    //if(ccw(s1.p1,s1.p2,s2.p1)==0&&ccw(s1.p1,s1.p2,s2.p2)==0) return s1.p1;
    
    Vector v1=l1.p2-l1.p1,v2=l2.p2-l2.p1;
    
    return l1.p1+v1*cross(v2,l2.p1-l1.p1)/cross(v2,v1);
}

Segment ParallelSegment(Segment s,double d){
    Vector v={-(s.p2-s.p1).y,(s.p2-s.p1).x};
    v=v/abs(v);
    
    s.p1=s.p1+v*d;
    s.p2=s.p2+v*d;
    
    return s;
}

class Circle{
public:
    Point c;
    double r;
    Circle(Point c=Point(),double r=0.0):c(c),r(r){}
};

Point CircleCenter(Point a,Point b,Point c){
    Point u=a-b,v=a-c;
    double m1=(norm(a)-norm(b))/2.0,m2=(norm(a)-norm(c))/2.0;
    
    Point res;
    if(cross(u,v)==0.0){
        res.x=1e9;
        res.y=1e9;
        
        return res;
    }
    res.x=(m1*v.y-m2*u.y)/cross(u,v);
    res.y=(m1*v.x-m2*u.x)/cross(v,u);
    
    return res;
}
//3点を通る円の中心を返す

pair<Point,Point> segCrossPpoints(Circle c,Line l){
    //assert(intersect(c,l));
    Vector pr=project(l,c.c);
    Vector e=(l.p2-l.p1)/abs(l.p2-l.p1);
    double base=sqrt(c.r*c.r-norm(pr-c.c));
    return make_pair(pr+e*base,pr-e*base);
}

double arg(Vector p){return atan2(p.y,p.x);}
Vector polar(double a,double r){return Point(cos(r)*a,sin(r)*a);}

pair<Point,Point> getCrossPoints(Circle c1,Circle c2){
    //assert(intersect(c1,c2));
    double d=abs(c1.c-c2.c);
    double a=acos((c1.r*c1.r+d*d-c2.r*c2.r)/(2*c1.r*d));
    double t=arg(c2.c-c1.c);
    return make_pair(c1.c+polar(c1.r,t+a),c1.c+polar(c1.r,t-a));
}

vector<Line> Commontangent(Circle c1,Circle c2){
    vector<Line> res;
    Point p=c2.c-c1.c;
    
    if(abs(p)>=(c1.r+c2.r)){
        Point a,b;
        a.x=c1.r*(p.x*(c1.r+c2.r)+p.y*sqrt(norm(p)-(c1.r+c2.r)*(c1.r+c2.r)))/norm(p);
        a.y=c1.r*(p.y*(c1.r+c2.r)-p.x*sqrt(norm(p)-(c1.r+c2.r)*(c1.r+c2.r)))/norm(p);
        
        b.x=c1.r*(p.x*(c1.r+c2.r)-p.y*sqrt(norm(p)-(c1.r+c2.r)*(c1.r+c2.r)))/norm(p);
        b.y=c1.r*(p.y*(c1.r+c2.r)+p.x*sqrt(norm(p)-(c1.r+c2.r)*(c1.r+c2.r)))/norm(p);
        
        res.push_back(Line{a+c1.c,a+c1.c+Point{-a.y,a.x}});
        if(!(a==b)){
            res.push_back(Line{b+c1.c,b+c1.c+Point{-b.y,b.x}});
        }
    }
    
    if(abs(p)>=abs(c1.r-c2.r)){
        Point a,b;
        a.x=c1.r*(p.x*(c1.r-c2.r)+p.y*sqrt(norm(p)-(c1.r-c2.r)*(c1.r-c2.r)))/norm(p);
        a.y=c1.r*(p.y*(c1.r-c2.r)-p.x*sqrt(norm(p)-(c1.r-c2.r)*(c1.r-c2.r)))/norm(p);
        
        b.x=c1.r*(p.x*(c1.r-c2.r)-p.y*sqrt(norm(p)-(c1.r-c2.r)*(c1.r-c2.r)))/norm(p);
        b.y=c1.r*(p.y*(c1.r-c2.r)+p.x*sqrt(norm(p)-(c1.r-c2.r)*(c1.r-c2.r)))/norm(p);
        
        res.push_back(Line{a+c1.c,a+c1.c+Point{-a.y,a.x}});
        if(!(a==b)){
            res.push_back(Line{b+c1.c,b+c1.c+Point{-b.y,b.x}});
        }
    }
    
    return res;
}

typedef vector<Point> Polygon;

/*
 IN 2
 ON 1
 OUT 0
 */

int contains(Polygon g,Point p){
    int n=int(g.size());
    bool x=false;
    for(int i=0;i<n;i++){
        Point a=g[i]-p,b=g[(i+1)%n]-p;
        if(a.y>b.y) swap(a,b);
        if(a.y<eps&&eps<b.y&&cross(a,b)>eps) x=!x;
    }
    return (x?2:0);
}

Polygon andrewScan(Polygon s,bool ok){
    Polygon u,l;
    sort(all(s));
    
    if(int(s.size())<3) return s;
    int n=int(s.size());
    
    u.push_back(s[0]);
    u.push_back(s[1]);
    
    l.push_back(s[n-1]);
    l.push_back(s[n-2]);
    
    if(ok){
        for(int i=2;i<n;i++){
            for(int j=int(u.size());j>=2&&ccw(u[j-2],u[j-1],s[i])==counter_clockwise;j--){
                u.pop_back();
            }
            u.push_back(s[i]);
        }
        
        for(int i=int(s.size())-3;i>=0;i--){
            for(int j=int(l.size());j>=2&&ccw(l[j-2],l[j-1],s[i])==counter_clockwise;j--){
                l.pop_back();
            }
            l.push_back(s[i]);
        }
    }
    
    if(!ok){
        for(int i=2;i<n;i++){
            for(int j=int(u.size());j>=2&&ccw(u[j-2],u[j-1],s[i])!=clockwise;j--){
                u.pop_back();
            }
            u.push_back(s[i]);
        }
        
        for(int i=int(s.size())-3;i>=0;i--){
            for(int j=int(l.size());j>=2&&ccw(l[j-2],l[j-1],s[i])!=clockwise;j--){
                l.pop_back();
            }
            l.push_back(s[i]);
        }
    }
    
    reverse(all(l));
    
    for(int i=int(u.size())-2;i>=1;i--) l.push_back(u[i]);
    
    return l;
}//ok==1なら辺の上も含める

Polygon convex_cut(const Polygon& P, const Line& l) {
    Polygon Q;
    for(int i=0;i<si(P);i++){
        Point A=P[i],B=P[(i+1)%si(P)];
        if(ccw(l.p1,l.p2,A)!=-1)Q.push_back(A);
        if(ccw(l.p1,l.p2,A)*ccw(l.p1,l.p2,B)<0) Q.push_back(getCrossPointL(Line{A,B},l));
    }
    return Q;
}

double area(Point a,Point b,Point c){
    b=b-a;
    c=c-a;
    return abs(b.x*c.y-b.y*c.x)/2.0;
}

double area(Polygon &P){
    if(si(P)==0) return 0.0;
    double res=0;
    Point c={0.0,0.0};
    for(int i=0;i<si(P);i++){
        c=c+P[i];
    }
    c=c/si(P);
    
    for(int i=0;i<si(P);i++){
        res+=area(c,P[i],P[(i+1)%si(P)]);
    }
    
    return res;
}

int dp[MAX];

int main(){
    
    std::ifstream in("text.txt");
    std::cin.rdbuf(in.rdbuf());
    cin.tie(0);
    ios::sync_with_stdio(false);
    
    while(1){
        int N;cin>>N;
        if(N==0) break;
        Point s,t;
        cin>>s.x>>s.y>>t.x>>t.y;
        
        vector<Circle> C(N);
        for(int i=0;i<N;i++) cin>>C[i].c.x>>C[i].c.y>>C[i].r;
        
        sort(all(C),[](auto a,auto b){
            return a.r<b.r;
        });
        
        for(int i=0;i<N;i++) dp[i]=-INF;
        
        for(int i=0;i<N;i++){
            int cnt=0;
            if(getDistance(C[i].c,s)<C[i].r) cnt++;
            if(getDistance(C[i].c,t)<C[i].r) cnt++;
            
            if(cnt==1){
                dp[i]=1;
                for(int j=0;j<i;j++){
                    if(C[j].r==C[i].r) continue;
                    
                    double d=getDistance(C[j].c,C[i].c);
                    
                    if(d+C[j].r<C[i].r) chmax(dp[i],dp[j]+1);
                }
            }
        }
        
        int ans=0;
        
        for(int i=0;i<N;i++){
            for(int j=0;j<N;j++){
                if(dp[i]>=1&&dp[j]>=1){
                    auto l=Commontangent(C[i],C[j]);
                    if(si(l)==4) chmax(ans,dp[i]+dp[j]);
                }
            }
            chmax(ans,dp[i]);
        }
        
        cout<<ans<<endl;
    }
}
accuracy: 1
time_ms: 440
memory_kb: 3572
final_rank: 15

code_snippet: #include <bits/stdc++.h>
#define rep(i, n) for (ll i = 0; i < (n); ++i)
#define repr(i, n) for (int i = (n); i >= 0; --i)
#define FOR(i, m, n) for (int i = (m); i < (n); ++i)
#define FORR(i, m, n) for (int i = (m); i >= (n); --i)
#define equals(a, b) (fabs((a) - (b)) < EPS)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
const ll mod = 1000000007;
//const ll mod = 998244353;
const int inf = 1e9 + 10;
const ll INF = 1e18;
const ld EPS = 1e-10;
const int dx[8] = {1, 0, -1, 0, 1, -1, -1, 1};
const int dy[8] = {0, 1, 0, -1, 1, 1, -1, -1};
template<class T> bool chmax(T &a, const T &b) { if (a<b) { a=b; return 1; } return 0; }
template<class T> bool chmin(T &a, const T &b) { if (a>b) { a=b; return 1; } return 0; }
typedef complex<ll> P;

int n;
P s, t;
P p[1005];
vector<P> G[10005];

void init() {
  rep(i, 10005) G[i].clear();
}

void solve() {
  vector<P> a, b;
  vector<ll> ar, br;
  rep(i, 10005) {
    for (P p: G[i]) {
      if (norm(p - s) < i * i) {
        a.push_back(p);
        ar.push_back(i);
      }
      else {
        b.push_back(p);
        br.push_back(i);
      }
    }
  }
  int ans = 0;
  vector<int> dpa(a.size(), 1), dpb(b.size(), 1);
  rep(i, a.size()) {
    rep(j, i) {
      if (norm(a[i] - a[j]) < (ar[i] - ar[j]) * (ar[i] - ar[j])) {
        chmax(dpa[i], dpa[j] + 1);
      }
    }
    chmax(ans, dpa[i]);
  }
  rep(i, b.size()) {
    rep(j, i) {
      if (norm(b[i] - b[j]) < (br[i] - br[j]) * (br[i] - br[j])) {
        chmax(dpb[i], dpb[j] + 1);
      }
    }
    chmax(ans, dpb[i]);
  }
  rep(i, a.size()) {
    rep(j, b.size()) {
      if (norm(a[i] - b[j]) > (ar[i] + br[j]) * (ar[i] + br[j])) {
        chmax(ans, dpa[i] + dpb[j]);
      }
    }
  }
  cout << ans << '\n';
}

int main() {
  ios::sync_with_stdio(0);
  cin.tie(0);
  cout << fixed << setprecision(25);

  while (cin >> n, n) {
    init();

    ll sx, sy, tx, ty;
    cin >> sx >> sy >> tx >> ty;
    s = P(sx, sy), t = P(tx, ty);
    rep(i, n) {
      ll px, py, r;
      cin >> px >> py >> r;
      P p = P(px, py);
      if (norm(p - t) < r * r && norm(p - s) < r * r) continue;
      if (norm(p - t) > r * r && norm(p - s) > r * r) continue;
      G[r].push_back(p);
    }

    solve();
  }

  




  
  return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 3500
final_rank: 9

code_snippet: #include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll, ll> l_l;
typedef pair<int, int> i_i;
template<class T>
inline bool chmax(T &a, T b) {
    if(a < b) {
        a = b;
        return true;
    }
    return false;
}

template<class T>
inline bool chmin(T &a, T b) {
    if(a > b) {
        a = b;
        return true;
    }
    return false;
}

/*
const long double EPS = 1e-10;
const long long INF = 1e18;
const long double PI = acos(-1.0L);
*/
using Real = double;
using Point = complex< Real >;
const Real EPS = 1e-8, PI = acos(-1);

inline bool eq(Real a, Real b) { return fabs(b - a) < EPS; }

Point operator*(const Point &p, const Real &d) {
  return Point(real(p) * d, imag(p) * d);
}

istream &operator>>(istream &is, Point &p) {
  Real a, b;
  is >> a >> b;
  p = Point(a, b);
  return is;
}

ostream &operator<<(ostream &os, Point &p) {
  os << fixed << setprecision(10) << p.real() << " " << p.imag();
}

Point rotate(Real theta, const Point &p) {
  return Point(cos(theta) * p.real() - sin(theta) * p.imag(), sin(theta) * p.real() + cos(theta) * p.imag());
}

Real radian_to_degree(Real r) {
  return (r * 180.0 / PI);
}

Real degree_to_radian(Real d) {
  return (d * PI / 180.0);
}

Real get_angle(const Point &a, const Point &b, const Point &c) {
  const Point v(b - a), w(c - b);
  Real alpha = atan2(v.imag(), v.real()), beta = atan2(w.imag(), w.real());
  if(alpha > beta) swap(alpha, beta);
  Real theta = (beta - alpha);
  return min(theta, 2 * acos(-1) - theta);
}

namespace std {
  bool operator<(const Point &a, const Point &b) {
    return a.real() != b.real() ? a.real() < b.real() : a.imag() < b.imag();
  }
}


struct Line {
  Point a, b;

  Line() = default;

  Line(Point a, Point b) : a(a), b(b) {}

  Line(Real A, Real B, Real C) // Ax + By = C
  {
    if(eq(A, 0)) a = Point(0, C / B), b = Point(1, C / B);
    else if(eq(B, 0)) b = Point(C / A, 0), b = Point(C / A, 1);
    else a = Point(0, C / B), b = Point(C / A, 0);
  }

  friend ostream &operator<<(ostream &os, Line &p) {
    return os << p.a << " to " << p.b;
  }

  friend istream &operator>>(istream &is, Line &a) {
    return is >> a.a >> a.b;
  }
};

struct Segment : Line {
  Segment() = default;

  Segment(Point a, Point b) : Line(a, b) {}
};

struct Circle {
  Point p;
  Real r;

  Circle() = default;

  Circle(Point p, Real r) : p(p), r(r) {}
};

using Points = vector< Point >;
using Polygon = vector< Point >;
using Segments = vector< Segment >;
using Lines = vector< Line >;
using Circles = vector< Circle >;

Real cross(const Point &a, const Point &b) {
  return real(a) * imag(b) - imag(a) * real(b);
}

Real dot(const Point &a, const Point &b) {
  return real(a) * real(b) + imag(a) * imag(b);
}

// http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_1_C
int ccw(const Point &a, Point b, Point c) {
  b = b - a, c = c - a;
  if(cross(b, c) > EPS) return +1;  // "COUNTER_CLOCKWISE"
  if(cross(b, c) < -EPS) return -1; // "CLOCKWISE"
  if(dot(b, c) < 0) return +2;      // "ONLINE_BACK"
  if(norm(b) < norm(c)) return -2;  // "ONLINE_FRONT"
  return 0;                         // "ON_SEGMENT"
}

// http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_2_A
bool parallel(const Line &a, const Line &b) {
  return eq(cross(a.b - a.a, b.b - b.a), 0.0);
}

// http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_2_A
bool orthogonal(const Line &a, const Line &b) {
  return eq(dot(a.a - a.b, b.a - b.b), 0.0);
}

// http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_1_A
Point projection(const Line &l, const Point &p) {
  double t = dot(p - l.a, l.a - l.b) / norm(l.a - l.b);
  return l.a + (l.a - l.b) * t;
}

Point projection(const Segment &l, const Point &p) {
  double t = dot(p - l.a, l.a - l.b) / norm(l.a - l.b);
  return l.a + (l.a - l.b) * t;
}

// http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_1_B
Point reflection(const Line &l, const Point &p) {
  return p + (projection(l, p) - p) * 2.0;
}

bool intersect(const Line &l, const Point &p) {
  return abs(ccw(l.a, l.b, p)) != 1;
}

bool intersect(const Line &l, const Line &m) {
  return abs(cross(l.b - l.a, m.b - m.a)) > EPS || abs(cross(l.b - l.a, m.b - l.a)) < EPS;
}

bool intersect(const Segment &s, const Point &p) {
  return ccw(s.a, s.b, p) == 0;
}

bool intersect(const Line &l, const Segment &s) {
  return cross(l.b - l.a, s.a - l.a) * cross(l.b - l.a, s.b - l.a) < EPS;
}

Real distance(const Line &l, const Point &p);

bool intersect(const Circle &c, const Line &l) {
  return distance(l, c.p) <= c.r + EPS;
}

bool intersect(const Circle &c, const Point &p) {
  return abs(abs(p - c.p) - c.r) < EPS;
}

// http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_2_B
bool intersect(const Segment &s, const Segment &t) {
  return ccw(s.a, s.b, t.a) * ccw(s.a, s.b, t.b) <= 0 && ccw(t.a, t.b, s.a) * ccw(t.a, t.b, s.b) <= 0;
}

int intersect(const Circle &c, const Segment &l) {
  if(norm(projection(l, c.p) - c.p) - c.r * c.r > EPS) return 0;
  auto d1 = abs(c.p - l.a), d2 = abs(c.p - l.b);
  if(d1 < c.r + EPS && d2 < c.r + EPS) return 0;
  if(d1 < c.r - EPS && d2 > c.r + EPS || d1 > c.r + EPS && d2 < c.r - EPS) return 1;
  const Point h = projection(l, c.p);
  if(dot(l.a - h, l.b - h) < 0) return 2;
  return 0;
}

// http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_7_A&lang=jp
bool intersect(Circle c1, Circle c2) {
  if(c1.r < c2.r) swap(c1, c2);
  Real d = abs(c1.p - c2.p);
  if(c1.r + c2.r < d) return false;
  if(eq(c1.r + c2.r, d)) return true;
  if(c1.r - c2.r < d) return true;
  if(eq(c1.r - c2.r, d)) return true;
  return false;
}

Real distance(const Point &a, const Point &b) {
  return abs(a - b);
}

Real distance(const Line &l, const Point &p) {
  return abs(p - projection(l, p));
}

Real distance(const Line &l, const Line &m) {
  return intersect(l, m) ? 0 : distance(l, m.a);
}

Real distance(const Segment &s, const Point &p) {
  Point r = projection(s, p);
  if(intersect(s, r)) return abs(r - p);
  return min(abs(s.a - p), abs(s.b - p));
}

// http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_2_D
Real distance(const Segment &a, const Segment &b) {
  if(intersect(a, b)) return 0;
  return min({distance(a, b.a), distance(a, b.b), distance(b, a.a), distance(b, a.b)});
}

Real distance(const Line &l, const Segment &s) {
  if(intersect(l, s)) return 0;
  return min(distance(l, s.a), distance(l, s.b));
}

Point crosspoint(const Line &l, const Line &m) {
  Real A = cross(l.b - l.a, m.b - m.a);
  Real B = cross(l.b - l.a, l.b - m.a);
  if(eq(abs(A), 0.0) && eq(abs(B), 0.0)) return m.a;
  return m.a + (m.b - m.a) * B / A;
}

// http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_2_C
Point crosspoint(const Segment &l, const Segment &m) {
  return crosspoint(Line(l), Line(m));
}

// http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_7_D
pair< Point, Point > crosspoint(const Circle &c, const Line l) {
  Point pr = projection(l, c.p);
  Point e = (l.b - l.a) / abs(l.b - l.a);
  if(eq(distance(l, c.p), c.r)) return {pr, pr};
  double base = sqrt(c.r * c.r - norm(pr - c.p));
  return {pr - e * base, pr + e * base};
}

pair< Point, Point > crosspoint(const Circle &c, const Segment &l) {
  Line aa = Line(l.a, l.b);
  if(intersect(c, l) == 2) return crosspoint(c, aa);
  auto ret = crosspoint(c, aa);
  if(dot(l.a - ret.first, l.b - ret.first) < 0) ret.second = ret.first;
  else ret.first = ret.second;
  return ret;
}

// http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_7_E
pair< Point, Point > crosspoint(const Circle &c1, const Circle &c2) {
  Real d = abs(c1.p - c2.p);
  Real a = acos((c1.r * c1.r + d * d - c2.r * c2.r) / (2 * c1.r * d));
  Real t = atan2(c2.p.imag() - c1.p.imag(), c2.p.real() - c1.p.real());
  Point p1 = c1.p + Point(cos(t + a) * c1.r, sin(t + a) * c1.r);
  Point p2 = c1.p + Point(cos(t - a) * c1.r, sin(t - a) * c1.r);
  return {p1, p2};
}

// http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_7_F
pair< Point, Point > tangent(const Circle &c1, const Point &p2) {
  return crosspoint(c1, Circle(p2, sqrt(norm(c1.p - p2) - c1.r * c1.r)));
}

// http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_7_G
Lines tangent(Circle c1, Circle c2) {
  Lines ret;
  if(c1.r < c2.r) swap(c1, c2);
  Real g = norm(c1.p - c2.p);
  if(eq(g, 0)) return ret;
  Point u = (c2.p - c1.p) / sqrt(g);
  Point v = rotate(PI * 0.5, u);
  for(int s : {-1, 1}) {
    Real h = (c1.r + s * c2.r) / sqrt(g);
    if(eq(1 - h * h, 0)) {
      ret.emplace_back(c1.p + u * c1.r, c1.p + (u + v) * c1.r);
    } else if(1 - h * h > 0) {
      Point uu = u * h, vv = v * sqrt(1 - h * h);
      ret.emplace_back(c1.p + (uu + vv) * c1.r, c2.p - (uu + vv) * c2.r * s);
      ret.emplace_back(c1.p + (uu - vv) * c1.r, c2.p - (uu - vv) * c2.r * s);
    }
  }
  return ret;
}

// http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_3_B
bool is_convex(const Polygon &p) {
  int n = (int) p.size();
  for(int i = 0; i < n; i++) {
    if(ccw(p[(i + n - 1) % n], p[i], p[(i + 1) % n]) == -1) return false;
  }
  return true;
}

// http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_4_A
Polygon convex_hull(Polygon &p) {
  int n = (int) p.size(), k = 0;
  if(n <= 2) return p;
  sort(p.begin(), p.end());
  vector< Point > ch(2 * n);
  for(int i = 0; i < n; ch[k++] = p[i++]) {
    while(k >= 2 && cross(ch[k - 1] - ch[k - 2], p[i] - ch[k - 1]) < 0) --k;
  }
  for(int i = n - 2, t = k + 1; i >= 0; ch[k++] = p[i--]) {
    while(k >= t && cross(ch[k - 1] - ch[k - 2], p[i] - ch[k - 1]) < 0) --k;
  }
  ch.resize(k - 1);
  return ch;
}

// http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_3_C
enum {
  OUT, ON, IN
};
int contains(const Polygon &Q, const Point &p) {
  bool in = false;
  for(int i = 0; i < Q.size(); i++) {
    Point a = Q[i] - p, b = Q[(i + 1) % Q.size()] - p;
    if(a.imag() > b.imag()) swap(a, b);
    if(a.imag() <= 0 && 0 < b.imag() && cross(a, b) < 0) in = !in;
    if(cross(a, b) == 0 && dot(a, b) <= 0) return ON;
  }
  return in ? IN : OUT;
}


// http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=1033
void merge_segments(vector< Segment > &segs) {

  auto merge_if_able = [](Segment &s1, const Segment &s2) {
    if(abs(cross(s1.b - s1.a, s2.b - s2.a)) > EPS) return false;
    if(ccw(s1.a, s2.a, s1.b) == 1 || ccw(s1.a, s2.a, s1.b) == -1) return false;
    if(ccw(s1.a, s1.b, s2.a) == -2 || ccw(s2.a, s2.b, s1.a) == -2) return false;
    s1 = Segment(min(s1.a, s2.a), max(s1.b, s2.b));
    return true;
  };

  for(int i = 0; i < segs.size(); i++) {
    if(segs[i].b < segs[i].a) swap(segs[i].a, segs[i].b);
  }
  for(int i = 0; i < segs.size(); i++) {
    for(int j = i + 1; j < segs.size(); j++) {
      if(merge_if_able(segs[i], segs[j])) {
        segs[j--] = segs.back(), segs.pop_back();
      }
    }
  }
}

// http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=1033
vector< vector< int > > segment_arrangement(vector< Segment > &segs, vector< Point > &ps) {
  vector< vector< int > > g;
  int N = (int) segs.size();
  for(int i = 0; i < N; i++) {
    ps.emplace_back(segs[i].a);
    ps.emplace_back(segs[i].b);
    for(int j = i + 1; j < N; j++) {
      const Point p1 = segs[i].b - segs[i].a;
      const Point p2 = segs[j].b - segs[j].a;
      if(cross(p1, p2) == 0) continue;
      if(intersect(segs[i], segs[j])) {
        ps.emplace_back(crosspoint(segs[i], segs[j]));
      }
    }
  }
  sort(begin(ps), end(ps));
  ps.erase(unique(begin(ps), end(ps)), end(ps));

  int M = (int) ps.size();
  g.resize(M);
  for(int i = 0; i < N; i++) {
    vector< int > vec;
    for(int j = 0; j < M; j++) {
      if(intersect(segs[i], ps[j])) {
        vec.emplace_back(j);
      }
    }
    for(int j = 1; j < vec.size(); j++) {
      g[vec[j - 1]].push_back(vec[j]);
      g[vec[j]].push_back(vec[j - 1]);
    }
  }
  return (g);
}

// http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_4_C
Polygon convex_cut(const Polygon &U, Line l) {
  Polygon ret;
  for(int i = 0; i < U.size(); i++) {
    Point now = U[i], nxt = U[(i + 1) % U.size()];
    if(ccw(l.a, l.b, now) != -1) ret.push_back(now);
    if(ccw(l.a, l.b, now) * ccw(l.a, l.b, nxt) < 0) {
      ret.push_back(crosspoint(Line(now, nxt), l));
    }
  }
  return (ret);
}

// http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_3_A
Real area2(const Polygon &p) {
  Real A = 0;
  for(int i = 0; i < p.size(); ++i) {
    A += cross(p[i], p[(i + 1) % p.size()]);
  }
  return A;
}

// http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_7_H
Real area2(const Polygon &p, const Circle &c) {
  if(p.size() < 3) return 0.0;
  function< Real(Circle, Point, Point) > cross_area = [&](const Circle &c, const Point &a, const Point &b) {
    Point va = c.p - a, vb = c.p - b;
    Real f = cross(va, vb), ret = 0.0;
    if(eq(f, 0.0)) return ret;
    if(max(abs(va), abs(vb)) < c.r + EPS) return f;
    if(distance(Segment(a, b), c.p) > c.r - EPS) return c.r * c.r * arg(vb * conj(va));
    auto u = crosspoint(c, Segment(a, b));
    vector< Point > tot{a, u.first, u.second, b};
    for(int i = 0; i + 1 < tot.size(); i++) {
      ret += cross_area(c, tot[i], tot[i + 1]);
    }
    return ret;
  };
  Real A = 0;
  for(int i = 0; i < p.size(); i++) {
    A += cross_area(c, p[i], p[(i + 1) % p.size()]);
  }
  return A;
}

// http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_4_B
Real convex_diameter(const Polygon &p) {
  int N = (int) p.size();
  int is = 0, js = 0;
  for(int i = 1; i < N; i++) {
    if(p[i].imag() > p[is].imag()) is = i;
    if(p[i].imag() < p[js].imag()) js = i;
  }
  Real maxdis = norm(p[is] - p[js]);

  int maxi, maxj, i, j;
  i = maxi = is;
  j = maxj = js;
  do {
    if(cross(p[(i + 1) % N] - p[i], p[(j + 1) % N] - p[j]) >= 0) {
      j = (j + 1) % N;
    } else {
      i = (i + 1) % N;
    }
    if(norm(p[i] - p[j]) > maxdis) {
      maxdis = norm(p[i] - p[j]);
      maxi = i;
      maxj = j;
    }
  } while(i != is || j != js);
  return sqrt(maxdis);
}

// http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=CGL_5_A
Real closest_pair(Points ps) {
  if(ps.size() <= 1) throw (0);
  sort(begin(ps), end(ps));

  auto compare_y = [&](const Point &a, const Point &b) {
    return imag(a) < imag(b);
  };
  vector< Point > beet(ps.size());
  const Real INF = 1e18;

  function< Real(int, int) > rec = [&](int left, int right) {
    if(right - left <= 1) return INF;
    int mid = (left + right) >> 1;
    auto x = real(ps[mid]);
    auto ret = min(rec(left, mid), rec(mid, right));
    inplace_merge(begin(ps) + left, begin(ps) + mid, begin(ps) + right, compare_y);
    int ptr = 0;
    for(int i = left; i < right; i++) {
      if(abs(real(ps[i]) - x) >= ret) continue;
      for(int j = 0; j < ptr; j++) {
        auto luz = ps[i] - beet[ptr - j - 1];
        if(imag(luz) >= ret) break;
        ret = min(ret, abs(luz));
      }
      beet[ptr++] = ps[i];
    }
    return ret;
  };
  return rec(0, (int) ps.size());
}

bool contains(Circle a, Circle b) {
    double delta = distance(a.p, b.p);
    return delta <= a.r - b.r + EPS;
}

//const ll mod = 1000000007;
Point P[2];
Circles C[2];
int N;

int solve() {
    for(int i = 0; i < 2; i++) {
        cin >> P[i];
        C[i].clear();
    }
    for(int i = 0; i < N; i++) {
        Point p;
        cin >> p;
        int r;
        cin >> r;
        Circle c(p, r);
        bool check[2] = {false, false};
        for(int j = 0; j < 2; j++) {
            if(distance(p, P[j]) <= r + EPS) check[j] = true;
        }
        if(!(check[0] ^ check[1])) continue;
        for(int j = 0; j < 2; j++) {
            if(check[j]) C[j].push_back(c);
        }
    }
    /*
    for(int i = 0; i < 2; i++) {
        cerr << "---" << i << "---" << endl;
        for(auto c : C[i]) {
            cerr << c.p << " " << c.r << endl;
        }
    }
    */
    vector<ll> dp[2];
    ll ans = 0;
    for(int i = 0; i < 2; i++) {
        sort(C[i].begin(), C[i].end(), [](Circle a, Circle b) {
            return a.r < b.r;
        });
        for(int j = 0; j < C[i].size(); j++) {
           dp[i].push_back(1); 
           for(int k = 0; k < j; k++) {
               if(intersect(C[i][j], C[i][k])) continue;
               chmax(dp[i][j], dp[i][k] + 1);
           }
           chmax(ans, dp[i][j]);
        }
    }
    for(int i = 0; i < dp[0].size(); i++) {
        for(int j = 0; j < dp[1].size(); j++) {
            if(intersect(C[0][i], C[1][j])) continue;
            chmax(ans, dp[0][i] + dp[1][j]);
        }
    }
    cout << ans << endl;
    return 0;
}
int main() {
    while(cin >> N) {
        if(N == 0) break;
        solve();
    }
}
accuracy: 1
time_ms: 80
memory_kb: 3384
final_rank: 11

code_snippet: /**
 * 
 */

// header {{{
#include <bits/stdc++.h>
using namespace std;

#define CPP_STR(x) CPP_STR_I(x)
#define CPP_CAT(x,y) CPP_CAT_I(x,y)
#define CPP_STR_I(args...) #args
#define CPP_CAT_I(x,y) x ## y

#define SFINAE(pred...) std::enable_if_t<(pred), std::nullptr_t> = nullptr

#define ASSERT(expr...) assert((expr))

using i8  = int8_t;
using u8  = uint8_t;
using i16 = int16_t;
using u16 = uint16_t;
using i32 = int32_t;
using u32 = uint32_t;
using i64 = int64_t;
using u64 = uint64_t;

using f32 = float;
using f64 = double;
using f80 = __float80;
// }}}

constexpr i64 INF  = INT64_C(1'010'000'000'000'000'017);
constexpr f64 FINF = 1e100;

constexpr i64 MOD = INT64_C(1'000'000'007);
//constexpr i64 MOD = INT64_C(998'244'353);

constexpr f64 EPS = 1e-12;

constexpr f64 PI = 3.14159265358979323846;

// util {{{
#define FOR(i, start, end) for(i64 i = (start), CPP_CAT(i,xxxx_end)=(end); i < CPP_CAT(i,xxxx_end); ++i)
#define REP(i, n) FOR(i, 0, n)

#define ALL(f,c,...) (([&](decltype((c)) cccc) { return (f)(std::begin(cccc), std::end(cccc), ## __VA_ARGS__); })(c))

#define LIFT(f) ([](auto&&... args) -> decltype(auto) { return (f)(std::forward<decltype(args)>(args)...); })

template<typename C>
constexpr i64 SIZE(const C& c) noexcept { return static_cast<i64>(c.size()); }

template<typename T, size_t N>
constexpr i64 SIZE(const T (&)[N]) noexcept { return static_cast<i64>(N); }

template<typename T, SFINAE(is_signed<T>::value)>
constexpr T ABS(T x) noexcept {
    return x < 0 ? -x : x;
}

template<typename T>
constexpr i64 CMP(T x, T y) noexcept { return (y<x) - (x<y); }

template<typename T>
constexpr i64 SGN(T x) noexcept { return CMP(x,T(0)); }

template<typename T, typename U, typename Comp=less<>>
constexpr bool chmax(T& xmax, const U& x, Comp comp={}) noexcept {
    if(comp(xmax, x)) {
        xmax = x;
        return true;
    }
    return false;
}

template<typename T, typename U, typename Comp=less<>>
constexpr bool chmin(T& xmin, const U& x, Comp comp={}) noexcept {
    if(comp(x, xmin)) {
        xmin = x;
        return true;
    }
    return false;
}

template<typename BinaryFunc, typename UnaryFunc>
auto ON(BinaryFunc&& bf, UnaryFunc&& uf) {
    return [bf=forward<BinaryFunc>(bf),uf=forward<UnaryFunc>(uf)](const auto& x, const auto& y) {
        return bf(uf(x), uf(y));
    };
}

template<typename F>
auto LT_ON(F&& f) {
    return ON(less<>{}, forward<F>(f));
}

template<typename F>
auto GT_ON(F&& f) {
    return ON(greater<>{}, forward<F>(f));
}

template<typename F>
auto EQ_ON(F&& f) {
    return ON(equal_to<>{}, forward<F>(f));
}

template<typename F>
auto NE_ON(F&& f) {
    return ON(not_equal_to<>{}, forward<F>(f));
}

// tuple {{{
template<i64 I=0, typename F, typename... TS, SFINAE(sizeof...(TS) == I)>
void tuple_enumerate(tuple<TS...>&, F&&) {}

template<i64 I=0, typename F, typename... TS, SFINAE(sizeof...(TS) > I)>
void tuple_enumerate(tuple<TS...>& t, F&& f) {
    f(I, get<I>(t));
    tuple_enumerate<I+1>(t, forward<F>(f));
}

template<i64 I=0, typename F, typename... TS, SFINAE(sizeof...(TS) == I)>
void tuple_enumerate(const tuple<TS...>&, F&&) {}

template<i64 I=0, typename F, typename... TS, SFINAE(sizeof...(TS) > I)>
void tuple_enumerate(const tuple<TS...>& t, F&& f) {
    f(I, get<I>(t));
    tuple_enumerate<I+1>(t, forward<F>(f));
}
// }}}

// container {{{
template<typename T> struct is_container : false_type {};
template<typename T, size_t N> struct is_container<array<T,N>> : true_type {};
template<typename... Args> struct is_container<vector<Args...>> : true_type {};
template<typename... Args> struct is_container<deque<Args...>> : true_type {};
template<typename... Args> struct is_container<list<Args...>> : true_type {};
template<typename... Args> struct is_container<forward_list<Args...>> : true_type {};
template<typename... Args> struct is_container<set<Args...>> : true_type {};
template<typename... Args> struct is_container<multiset<Args...>> : true_type {};
template<typename... Args> struct is_container<unordered_set<Args...>> : true_type {};
template<typename... Args> struct is_container<unordered_multiset<Args...>> : true_type {};
template<typename... Args> struct is_container<map<Args...>> : true_type {};
template<typename... Args> struct is_container<multimap<Args...>> : true_type {};
template<typename... Args> struct is_container<unordered_map<Args...>> : true_type {};
template<typename... Args> struct is_container<unordered_multimap<Args...>> : true_type {};

template<typename T, typename Enable=void>
struct ProconHash {
    size_t operator()(const T& x) const noexcept {
        return hash<T>{}(x);
    }
};

template<typename T>
size_t procon_hash_value(const T& x) noexcept {
    return ProconHash<T>{}(x);
}

size_t procon_hash_combine(size_t h1, size_t h2) noexcept {
    constexpr size_t M = UINT64_C(0xc6a4a7935bd1e995);
    constexpr int    R = 47;

    h2 *= M;
    h2 ^= h2 >> R;
    h2 *= M;

    h1 ^= h2;
    h1 *= M;

    h1 += 0xe6546b64;

    return h1;
}

template<typename T1, typename T2>
struct ProconHash<pair<T1,T2>> {
    size_t operator()(const pair<T1,T2>& p) const noexcept {
        size_t h1 = procon_hash_value(p.first);
        size_t h2 = procon_hash_value(p.second);
        return procon_hash_combine(h1, h2);
    }
};

template<typename... TS>
struct ProconHash<tuple<TS...>> {
    size_t operator()(const tuple<TS...>& t) const noexcept {
        size_t h = 0;
        tuple_enumerate(t, [&h](i64, const auto& e) {
            h = procon_hash_combine(h, procon_hash_value(e));
        });
        return h;
    }
};

template<typename C>
struct ProconHash<C,enable_if_t<is_container<C>::value>> {
    size_t operator()(const C& c) const noexcept {
        size_t h = 0;
        for(const auto& e : c)
            h = procon_hash_combine(h, procon_hash_value(e));
        return h;
    }
};

template<typename T, typename Hash=ProconHash<T>, typename Eq=equal_to<T>>
using HashSet = unordered_set<T,Hash,Eq>;
template<typename K, typename V, typename Hash=ProconHash<K>, typename Eq=equal_to<K>>
using HashMap = unordered_map<K,V,Hash,Eq>;
template<typename T, typename Hash=ProconHash<T>, typename Eq=equal_to<T>>
using HashMultiset = unordered_multiset<T,Hash,Eq>;
template<typename K, typename V, typename Hash=ProconHash<K>, typename Eq=equal_to<K>>
using HashMultimap = unordered_multimap<K,V,Hash,Eq>;

template<typename T>
auto vec_make(i64 n, T x) {
    return vector<T>(n, x);
}

template<typename T, typename... Args, SFINAE(sizeof...(Args) >= 2)>
auto vec_make(i64 n, Args... args) {
    auto inner = vec_make<T>(args...);
    return vector<decltype(inner)>(n, inner);
}

template<typename T>
auto vec_reserve(i64 cap) {
    vector<T> res;
    res.reserve(cap);
    return res;
}

template<typename T=i64>
auto vec_iota(i64 n, T init={}) {
    vector<i64> res(n);
    ALL(iota, res, init);
    return res;
}

template<typename T, typename Comp, typename Cont=vector<T>>
auto priority_queue_make(const Comp& comp, Cont&& cont={}) {
    return priority_queue<T,remove_reference_t<Cont>,Comp>(comp, forward<Cont>(cont));
}

template<typename T, typename Comp>
auto priority_queue_reserve(const Comp& comp, i64 cap) {
    return priority_queue<T,vector<T>,Comp>(comp, vec_reserve<T>(cap));
}

template<typename T, size_t N, size_t... NS>
struct ArrayType {
    using type = array<typename ArrayType<T,NS...>::type,N>;
};

template<typename T, size_t N>
struct ArrayType<T,N> {
    using type = array<T,N>;
};

template<typename T, size_t... NS>
using Array = typename ArrayType<T,NS...>::type;

template<typename T, size_t N>
T& array_at(Array<T,N>& ary, i64 i) {
    return ary[i];
}

template<typename T, size_t N, size_t... NS, typename... Args>
T& array_at(Array<T,N,NS...>& ary, i64 i, Args... args) {
    return array_at<T,NS...>(ary[i], args...);
}

template<typename T, size_t N>
const T& array_at(const Array<T,N>& ary, i64 i) {
    return ary[i];
}

template<typename T, size_t N, size_t... NS, typename... Args>
const T& array_at(const Array<T,N,NS...>& ary, i64 i, Args... args) {
    return array_at<T,NS...>(ary[i], args...);
}

template<typename T, typename C>
T POP(stack<T,C>& stk) {
    T x = stk.top(); stk.pop();
    return x;
}

template<typename T, typename C>
T POP(queue<T,C>& que) {
    T x = que.front(); que.pop();
    return x;
}

template<typename T, typename C, typename Comp>
T POP(priority_queue<T,C,Comp>& que) {
    T x = que.top(); que.pop();
    return x;
}
// }}}

// fixpoint {{{
template<typename F>
class FixPoint {
public:
    explicit constexpr FixPoint(F&& f) : f_(forward<F>(f)) {}

    template<typename... Args>
    constexpr decltype(auto) operator()(Args&&... args) const {
        return f_(*this, forward<Args>(args)...);
    }

private:
    F f_;
};

template<typename F>
constexpr decltype(auto) FIX(F&& f) {
    return FixPoint<F>(forward<F>(f));
}

template<typename F, size_t... NS>
class FixPointMemo {
public:
    explicit FixPointMemo(F&& f) : f_(forward<F>(f)) {}

    template<typename... Args>
    decltype(auto) operator()(Args... args) const {
        using R = decltype(f_(*this,args...));
        static Array<bool,NS...> done {};
        static Array<R,NS...>    memo;

        if(!array_at<bool,NS...>(done,args...)) {
            array_at<R,NS...>(memo,args...) = f_(*this,args...);
            array_at<bool,NS...>(done,args...) = true;
        }
        return array_at<R,NS...>(memo,args...);
    }

private:
    F f_;
};

template<size_t... NS, typename F>
decltype(auto) FIXMEMO(F&& f) {
    return FixPointMemo<F,NS...>(forward<F>(f));
}
// }}}

// math {{{
/*constexpr*/ i64 GCD(i64 a, i64 b) noexcept {
    /*constexpr*/ auto f_gcd = FIX([](auto&& self, i64 aa, i64 bb) {
        if(bb == 0) return aa;
        return self(bb, aa%bb);
    });
    return f_gcd(ABS(a), ABS(b));
}

/*constexpr*/ i64 LCM(i64 a, i64 b) noexcept {
    ASSERT(a != 0 && b != 0);
    /*constexpr*/ auto f_gcd = FIX([](auto&& self, i64 aa, i64 bb) {
        if(bb == 0) return aa;
        return self(bb, aa%bb);
    });
    a = ABS(a);
    b = ABS(b);
    return a / f_gcd(a,b) * b;
}

/*constexpr*/ tuple<i64,i64,i64> EXTGCD(i64 a, i64 b) noexcept {
    /*constexpr*/ auto impl = FIX([](auto&& self, i64 aa, i64 bb) -> tuple<i64,i64,i64> {
        if(bb == 0) return make_tuple(aa, 1, 0);
        i64 g,x,y; tie(g,x,y) = self(bb, aa%bb);
        return make_tuple(g, y, x-(aa/bb)*y);
    });
    i64 g,x,y; tie(g,x,y) = impl(ABS(a), ABS(b));
    x *= SGN(a);
    y *= SGN(b);
    return make_tuple(g, x, y);
}
// }}}

// string {{{
auto str_reserve(i64 cap) {
    string res;
    res.reserve(cap);
    return res;
}
// }}}

// input {{{
template<typename T, typename Enable=void>
struct Scan {
    static T scan(istream& in) {
        T res;
        in >> res;
        return res;
    }
};

template<typename T, typename Enable=void>
struct Scan1;

template<typename T>
struct Scan1<T,enable_if_t<is_integral<T>::value && !is_same<T,bool>::value>> {
    static T scan1(istream& in) {
        return Scan<T>::scan(in) - 1;
    }
};

template<typename T1, typename T2>
struct Scan<pair<T1,T2>> {
    static pair<T1,T2> scan(istream& in) {
        T1 x = Scan<T1>::scan(in);
        T2 y = Scan<T2>::scan(in);
        return {x,y};
    }
};

template<typename T1, typename T2>
struct Scan1<pair<T1,T2>> {
    static pair<T1,T2> scan1(istream& in) {
        T1 x = Scan1<T1>::scan1(in);
        T2 y = Scan1<T2>::scan1(in);
        return {x,y};
    }
};

template<typename T>
tuple<T> tuple_scan_impl(istream& in) {
    return make_tuple(Scan<T>::scan(in));
}

template<typename T, typename... TS, SFINAE(sizeof...(TS) > 0)>
tuple<T,TS...> tuple_scan_impl(istream& in) {
    auto head = make_tuple(Scan<T>::scan(in));
    return tuple_cat(head, tuple_scan_impl<TS...>(in));
}

template<typename... TS>
struct Scan<tuple<TS...>> {
    static tuple<TS...> scan(istream& in) {
        return tuple_scan_impl<TS...>(in);
    }
};

template<typename T>
tuple<T> tuple_scan1_impl(istream& in) {
    return make_tuple(Scan1<T>::scan1(in));
}

template<typename T, typename... TS, SFINAE(sizeof...(TS) > 0)>
tuple<T,TS...> tuple_scan1_impl(istream& in) {
    auto head = make_tuple(Scan1<T>::scan1(in));
    return tuple_cat(head, tuple_scan1_impl<TS...>(in));
}

template<typename... TS>
struct Scan1<tuple<TS...>> {
    static tuple<TS...> scan1(istream& in) {
        return tuple_scan1_impl<TS...>(in);
    }
};

template<typename T=i64>
T RD() {
    return Scan<T>::scan(cin);
}

template<typename T=i64>
T RD1() {
    return Scan1<T>::scan1(cin);
}

template<typename T=i64>
auto RD_VEC(i64 n) {
    auto res = vec_reserve<T>(n);
    REP(_, n) {
        res.emplace_back(RD<T>());
    }
    return res;
}

template<typename T=i64>
auto RD1_VEC(i64 n) {
    auto res = vec_reserve<T>(n);
    REP(_, n) {
        res.emplace_back(RD1<T>());
    }
    return res;
}

template<typename T=i64>
auto RD_VEC2(i64 h, i64 w) {
    auto res = vec_reserve<vector<T>>(h);
    REP(_, h) {
        res.emplace_back(RD_VEC<T>(w));
    }
    return res;
}

template<typename T=i64>
auto RD1_VEC2(i64 h, i64 w) {
    auto res = vec_reserve<vector<T>>(h);
    REP(_, h) {
        res.emplace_back(RD1_VEC<T>(w));
    }
    return res;
}
// }}}

// output {{{
template<typename T, typename Enable=void>
struct Fmt {
    static void fmt(ostream& out, const T& x) { out << x; }
};

template<typename T>
void fmt_write(ostream& out, const T& x) {
    Fmt<T>::fmt(out, x);
}

template<typename... TS>
struct Fmt<tuple<TS...>> {
    static void fmt(ostream& out, const tuple<TS...>& t) {
        tuple_enumerate(t, [&out](i64 i, const auto& e) {
            if(i != 0) out << ' ';
            fmt_write(out, e);
        });
    }
};

template<typename T1, typename T2>
struct Fmt<pair<T1,T2>> {
    static void fmt(ostream& out, const pair<T1,T2>& p) {
        return fmt_write(out, make_tuple(p.first,p.second));
    }
};

template<typename C>
struct Fmt<C,enable_if_t<is_container<C>::value>> {
    static void fmt(ostream& out, const C& c) {
        for(auto it = begin(c); it != end(c); ++it) {
            if(it != begin(c)) out << ' ';
            fmt_write(out, *it);
        }
    }
};

void PRINT() {}

template<typename T, typename... TS>
void PRINT(const T& x, const TS&... args) {
    fmt_write(cout, x);
    if(sizeof...(args) > 0) {
        cout << ' ';
        PRINT(args...);
    }
}

template<typename... TS>
void PRINTLN(const TS&... args) {
    PRINT(args...);
    cout << '\n';
}
// }}}

// debug {{{
template<typename T, typename Enable=void>
struct Dbg {
    static void dbg(ostream& out, const T& x) { out << x; }
};

template<typename T>
void dbg_write(ostream& out, const T& x) {
    Dbg<T>::dbg(out, x);
}

template<>
struct Dbg<i64> {
    static void dbg(ostream& out, i64 x) {
        if(x == INF)
            out << "INF";
        else if(x == -INF)
            out << "-INF";
        else
            out << x;
    }
};

template<>
struct Dbg<f64> {
    static void dbg(ostream& out, f64 x) {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wfloat-equal"
        if(x == FINF)
            out << "FINF";
        else if(x == -FINF)
            out << "-FINF";
        else
            out << x;
#pragma GCC diagnostic pop
    }
};

template<typename T, size_t N>
struct Dbg<T[N]> {
    static void dbg(ostream& out, const T (&ary)[N]) {
        out << "[";
        REP(i, N) {
            if(i != 0) out << ",";
            dbg_write(out, ary[i]);
        }
        out << "]";
    }
};

template<size_t N>
struct Dbg<char[N]> {
    static void dbg(ostream& out, const char (&s)[N]) {
        out << s;
    }
};

template<typename... TS>
struct Dbg<tuple<TS...>> {
    static void dbg(ostream& out, const tuple<TS...>& t) {
        out << "(";
        tuple_enumerate(t, [&out](i64 i, const auto& e) {
            if(i != 0) out << ",";
            dbg_write(out, e);
        });
        out << ")";
    }
};

template<typename T1, typename T2>
struct Dbg<pair<T1,T2>> {
    static void dbg(ostream& out, const pair<T1,T2>& p) {
        return dbg_write(out, make_tuple(p.first,p.second));
    }
};

template<typename C>
struct Dbg<C,enable_if_t<is_container<C>::value>> {
    static void dbg(ostream& out, const C& c) {
        out << "[";
        for(auto it = begin(c); it != end(c); ++it) {
            if(it != begin(c)) out << ",";
            dbg_write(out, *it);
        }
        out << "]";
    }
};

template<typename T, typename C>
struct Dbg<stack<T,C>> {
    static void dbg(ostream& out, stack<T,C> stk) {
        out << "[";
        while(!stk.empty()) {
            dbg_write(out,stk.top()); stk.pop();
            if(!stk.empty()) out << ",";
        }
        out << "]";
    }
};

template<typename T, typename C>
struct Dbg<queue<T,C>> {
    static void dbg(ostream& out, queue<T,C> que) {
        out << "[";
        while(!que.empty()) {
            dbg_write(out,que.front()); que.pop();
            if(!que.empty()) out << ",";
        }
        out << "]";
    }
};

template<typename T, typename C, typename Comp>
struct Dbg<priority_queue<T,C,Comp>> {
    static void dbg(ostream& out, priority_queue<T,C,Comp> que) {
        out << "[";
        while(!que.empty()) {
            dbg_write(out,que.top()); que.pop();
            if(!que.empty()) out << ",";
        }
        out << "]";
    }
};

template<typename T>
void DBG_IMPL(i64 line, const char* expr, const T& value) {
    cerr << "[L " << line << "]: ";
    cerr << expr << " = ";
    dbg_write(cerr, value);
    cerr << "\n";
}

void DBG_IMPL_HELPER() {}

template<typename T, typename... TS>
void DBG_IMPL_HELPER(const T& x, const TS&... args) {
    dbg_write(cerr, x);
    if(sizeof...(args) > 0) {
        cerr << ",";
        DBG_IMPL_HELPER(args...);
    }
}

template<typename... TS>
void DBG_IMPL(i64 line, const char* expr, const TS&... value) {
    cerr << "[L " << line << "]: ";
    cerr << "(" << expr << ") = (";
    DBG_IMPL_HELPER(value...);
    cerr << ")\n";
}

template<size_t N, typename T, SFINAE(rank<T>::value == 0)>
void DBG_DP_IMPL_HELPER(ostream& out, const T& x, const array<i64,N>&, const array<i64,N>&) {
    dbg_write(out, x);
}

template<size_t N, typename T, SFINAE(rank<T>::value > 0)>
void DBG_DP_IMPL_HELPER(ostream& out, const T& x, const array<i64,N>& sizes, const array<i64,N>& offs) {
    i64 k   = N - rank<T>::value;
    i64 off = offs[k];
    i64 siz = sizes[k];
    if(siz == 0) siz = extent<T>::value - off;

    out << "[";
    FOR(i, off, off+siz) {
        if(i != off) out << ",";
        DBG_DP_IMPL_HELPER(out, x[i], sizes, offs);
    }
    out << "]";
}

template<typename T, SFINAE(rank<T>::value > 0)>
void DBG_DP_IMPL(i64 line, const char* expr, const T& dp,
                 const array<i64,rank<T>::value>& sizes={},
                 const array<i64,rank<T>::value>& offs={})
{
    cerr << "[L " << line << "]: ";
    cerr << expr << " = ";
    DBG_DP_IMPL_HELPER<rank<T>::value>(cerr, dp, sizes, offs);
    cerr << "\n";
}

template<typename T>
void DBG_GRID_IMPL(i64 line, const char* expr, const vector<T>& grid) {
    cerr << "[L " << line << "]: ";
    cerr << expr << ":\n";
    for(const auto& row : grid) {
        dbg_write(cerr, row);
        cerr << "\n";
    }
    cerr << "\n";
}

#ifdef PROCON_LOCAL
    #define DBG(args...) DBG_IMPL(__LINE__, CPP_STR_I(args), args)
    #define DBG_DP(args...) DBG_DP_IMPL(__LINE__, CPP_STR_I(args), args)
    #define DBG_GRID(args...) DBG_GRID_IMPL(__LINE__, CPP_STR_I(args), args)
#else
    #define DBG(args...)
    #define DBG_DP(args...)
    #define DBG_GRID(args...)
#endif
// }}}

// modint {{{
template<typename Mod>
class ModIntT {
private:
    i64 v_;  // [0,Mod::value)

    static i64 mod() { return Mod::value; }

    static i64 normalize(i64 x) {
        i64 res = x % mod();
        if(res < 0) res += mod();
        return res;
    }

public:
    ModIntT() : v_(0) {}
    ModIntT(i64 v) : v_(normalize(v)) {}

    explicit operator i64() const { return v_; }

    ModIntT operator-() const { return ModIntT(-v_); }

    ModIntT& operator+=(ModIntT rhs) {
        v_ = normalize(v_ + rhs.v_);
        return *this;
    }
    ModIntT& operator-=(ModIntT rhs) {
        v_ = normalize(v_ - rhs.v_);
        return *this;
    }
    ModIntT& operator*=(ModIntT rhs) {
        v_ = normalize(v_ * rhs.v_);
        return *this;
    }

    ModIntT& operator++() { return *this += 1; }
    ModIntT& operator--() { return *this -= 1; }
    ModIntT operator++(int) { return exchange(*this, *this+1); }
    ModIntT operator--(int) { return exchange(*this, *this-1); }

    ModIntT inv() const {
        i64 g,x; tie(g,x,ignore) = EXTGCD(v_, mod());
        ASSERT(g == 1);
        return ModIntT(x);
    }
};

template<typename Mod>
ModIntT<Mod> operator+(ModIntT<Mod> lhs, ModIntT<Mod> rhs) { return ModIntT<Mod>(lhs) += rhs; }
template<typename Mod>
ModIntT<Mod> operator+(ModIntT<Mod> lhs, i64 rhs) { return ModIntT<Mod>(lhs) += rhs; }
template<typename Mod>
ModIntT<Mod> operator+(i64 lhs, ModIntT<Mod> rhs) { return ModIntT<Mod>(rhs) += lhs; }
template<typename Mod>
ModIntT<Mod> operator-(ModIntT<Mod> lhs, ModIntT<Mod> rhs) { return ModIntT<Mod>(lhs) -= rhs; }
template<typename Mod>
ModIntT<Mod> operator-(ModIntT<Mod> lhs, i64 rhs) { return ModIntT<Mod>(lhs) -= rhs; }
template<typename Mod>
ModIntT<Mod> operator-(i64 lhs, ModIntT<Mod> rhs) { return ModIntT<Mod>(rhs) -= lhs; }
template<typename Mod>
ModIntT<Mod> operator*(ModIntT<Mod> lhs, ModIntT<Mod> rhs) { return ModIntT<Mod>(lhs) *= rhs; }
template<typename Mod>
ModIntT<Mod> operator*(ModIntT<Mod> lhs, i64 rhs) { return ModIntT<Mod>(lhs) *= rhs; }
template<typename Mod>
ModIntT<Mod> operator*(i64 lhs, ModIntT<Mod> rhs) { return ModIntT<Mod>(rhs) *= lhs; }

template<typename Mod>
bool operator==(ModIntT<Mod> lhs, ModIntT<Mod> rhs) { return i64(lhs) == i64(rhs); }
template<typename Mod>
bool operator==(ModIntT<Mod> lhs, i64 rhs) { return lhs == ModIntT<Mod>(rhs); }
template<typename Mod>
bool operator==(i64 lhs, ModIntT<Mod> rhs) { return ModIntT<Mod>(lhs) == rhs; }
template<typename Mod>
bool operator!=(ModIntT<Mod> lhs, ModIntT<Mod> rhs) { return !(lhs == rhs); }
template<typename Mod>
bool operator!=(ModIntT<Mod> lhs, i64 rhs) { return !(lhs == rhs); }
template<typename Mod>
bool operator!=(i64 lhs, ModIntT<Mod> rhs) { return !(lhs == rhs); }

template<typename Mod>
struct ProconHash<ModIntT<Mod>> {
    size_t operator()(ModIntT<Mod> x) const noexcept {
        return procon_hash_value(i64(x));
    }
};

template<typename Mod>
struct Scan<ModIntT<Mod>> {
    static ModIntT<Mod> scan(istream& in) {
        i64 v = Scan<i64>::scan(in);
        return ModIntT<Mod>(v);
    }
};

template<typename Mod>
struct Fmt<ModIntT<Mod>> {
    static void fmt(ostream& out, ModIntT<Mod> x) {
        fmt_write(out, i64(x));
    }
};

template<typename Mod>
struct Dbg<ModIntT<Mod>> {
    static void dbg(ostream& out, ModIntT<Mod> x) {
        dbg_write(out, i64(x));
    }
};

template<i64 M>
using ModIntC = ModIntT<integral_constant<i64,M>>;

using ModInt = ModIntC<MOD>;
// }}}
// }}}

// init {{{
struct ProconInit {
    static constexpr int IOS_PREC = 15;
    static constexpr bool AUTOFLUSH = false;

    ProconInit() {
        cin.tie(nullptr);
        ios::sync_with_stdio(false);
        cin.exceptions(ios::failbit | ios::badbit);
        cout << fixed << setprecision(IOS_PREC);
#ifdef PROCON_LOCAL
        cerr << fixed << setprecision(2);
#endif
        if(AUTOFLUSH)
            cout << unitbuf;
    }
} PROCON_INIT;
// }}}

//--------------------------------------------------------------------

i64 NORM(i64 x1, i64 y1, i64 x2, i64 y2) {
    i64 dx = x1 - x2;
    i64 dy = y1 - y2;
    return dx*dx + dy*dy;
}

auto make_graph(const vector<tuple<i64,i64,i64>>& cs) {
    i64 n = SIZE(cs);

    vector<vector<i64>> g(n);
    REP(i, n) REP(j, n) {
        if(i == j) continue;
        i64 x1,y1,r1; tie(x1,y1,r1) = cs[i];
        i64 x2,y2,r2; tie(x2,y2,r2) = cs[j];

        if(f64(r1) > sqrt(NORM(x1,y1,x2,y2)) + f64(r2))
            g[i].emplace_back(j);
    }

    return g;
}

auto calc_dp(const vector<vector<i64>>& g) {
    i64 n = SIZE(g);

    vector<i64> dp(n, 0);
    auto dfs = FIX([&g,&dp](auto&& self, i64 v) -> i64 {
        if(dp[v] > 0) return dp[v];
        i64 res = 1;
        for(i64 to : g[v])
            chmax(res, 1+self(to));
        return dp[v] = res;
    });
    REP(v, n) {
        dfs(v);
    }

    return dp;
}

void solve(i64 N) {
    i64 sx = RD();
    i64 sy = RD();
    i64 tx = RD();
    i64 ty = RD();
    auto C = RD_VEC<tuple<i64,i64,i64>>(N);

    vector<tuple<i64,i64,i64>> scs;
    vector<tuple<i64,i64,i64>> tcs;
    for(const auto& c : C) {
        i64 x,y,r; tie(x,y,r) = c;
        bool s_in = NORM(x,y,sx,sy) < r*r;
        bool t_in = NORM(x,y,tx,ty) < r*r;
        if(s_in == t_in) continue;

        if(s_in)
            scs.emplace_back(x,y,r);
        else
            tcs.emplace_back(x,y,r);
    }
    i64 sn = SIZE(scs);
    i64 tn = SIZE(tcs);
    DBG(sn, scs);
    DBG(tn, tcs);

    auto sg = make_graph(scs);
    auto tg = make_graph(tcs);
    DBG(sg);
    DBG(tg);

    auto sdp = calc_dp(sg);
    auto tdp = calc_dp(tg);
    DBG(sdp);
    DBG(tdp);

    i64 ans = 0;
    // scs のみを使う
    if(sn > 0)
        chmax(ans, *ALL(max_element, sdp));
    // tcs のみを使う
    if(tn > 0)
        chmax(ans, *ALL(max_element, tdp));
    // scs, tcs を両方使う
    REP(i, sn) REP(j, tn) {
        i64 x1,y1,r1; tie(x1,y1,r1) = scs[i];
        i64 x2,y2,r2; tie(x2,y2,r2) = tcs[j];
        if(NORM(x1,y1,x2,y2) <= (r1+r2)*(r1+r2)) continue;

        chmax(ans, sdp[i] + tdp[j]);
    }

    PRINTLN(ans);
}

signed main() {
    for(;;) {
        i64 N = RD();
        if(N == 0) break;
        solve(N);
    }

    return 0;
}
accuracy: 1
time_ms: 70
memory_kb: 8516
final_rank: 18

code_snippet: #include <bits/stdc++.h>
using namespace std;

using Float = double;
using Point = complex<Float>;
struct Circle{ Point center; Float r; };

const Float EPS = 1e-8;

Float distance(Point &p1,Point &p2){
    return abs(p1 - p2);
}

bool isContain(Circle &c,Point &p){
    return (distance(c.center,p) <= c.r + EPS);
}

bool isContain(Circle &c1,Circle &c2){
    return (c1.r - EPS>= c2.r + distance(c1.center,c2.center));
}

bool isIntersect(Circle &c1,Circle &c2){
    return (distance(c1.center,c2.center) <= c1.r + c2.r + EPS);
}

void calcContainable(vector<Circle> &circs,vector<int> &ret){
    sort(circs.begin(),circs.end(),[](const Circle &c1,const Circle &c2){
        return c1.r < c2.r;
    });
    ret.resize(circs.size());
    for(int i = 0;i < circs.size();i++){
        ret[i] = 1;
        for(int j = 0;j < i;j++){
            if(isContain(circs[i],circs[j])){
                ret[i] = max(ret[i],ret[j] + 1);
            }
        }
    }
}

signed main(){
    int n;
    while(cin >> n,n){
        Float xs,ys,xt,yt;
        vector<Circle> circleS,circleT;
        int ans = 0;
        cin >> xs >> ys >> xt >> yt;
        Point ps = Point(xs,ys),pt = Point(xt,yt);
        for(int i = 0;i < n;i++){
            Float x,y,r;
            cin >> x >> y >> r;
            Circle circ = {Point(x,y),r};
            if(isContain(circ,ps) ^ isContain(circ,pt)){
                (isContain(circ,ps) ? circleS : circleT).push_back(circ);
            }
        }
        vector<int> containableS,containableT;
        calcContainable(circleS,containableS);
        calcContainable(circleT,containableT);
        for(int i = 0;i < circleS.size();i++) ans = max(ans,containableS[i]);
        for(int i = 0;i < circleT.size();i++) ans = max(ans,containableT[i]);
        for(int i = 0;i < circleS.size();i++){
            for(int j = 0;j < circleT.size();j++){
                if(!isIntersect(circleS[i],circleT[j])) ans = max(ans,containableS[i] + containableT[j]);
            }
        }
        cout << ans << endl;
    }
    return 0;
}
accuracy: 1
time_ms: 70
memory_kb: 3144
final_rank: 8