同じ高さで到達可能なモノを1つにまとめる。
まとめると、よくあるDPになる。
const int N = 50 + 1; typedef complex<double> Point; double dot(Point a, Point b) { return (a.real() * b.real() + a.imag() * b.imag()); } double cross(Point a, Point b) { return (a.real() * b.imag() - a.imag() * b.real()); } double distance_lp(Point a1, Point a2, Point b) { if(dot(a2-a1, b-a1) < EPS)return abs(b-a1); if(dot(a1-a2, b-a2) < EPS)return abs(b-a2); return abs(cross(a2-a1, b-a1)) / abs(a2-a1); } double distance_ll(Point a1, Point a2, Point b1, Point b2) { double a = min(distance_lp(a1, a2, b1), distance_lp(a1, a2, b2)); double b = min(distance_lp(b1, b2, a1), distance_lp(b1, b2, a2)); return min(a, b); } class DisjointSet{ public: vector<int> rank, p; DisjointSet(int size) { rank.resize(size, 0); p.resize(size, 0); } void make(int a) { rank[a] = 0; p[a] = a; } void join(int a, int b) { link(find(a), find(b)); } int find(int a) { return (a == p[a])? a : p[a] = find(p[a]); } bool isSameSet(int a, int b) { return find(a) == find(b); } void link (int a, int b) { if(rank[a] > rank[b]) p[b] = a; else { p[a] = b; if(rank[a] == rank[b]) rank[b]++; } } }; int K; vector<int> X, Y, L, S; bool reach(int i, int j) { Point a1(X[i], Y[i]); Point a2(X[i] + L[i], Y[i]); Point b1(X[j], Y[j]); Point b2(X[j] + L[j], Y[j]); return distance_ll(a1, a2, b1, b2) <= (double)K; } bool g[N][N]; int ss[N]; int memo[N]; int rec(int n) { int &ret = memo[n]; if (ret != -1) return ret; int mx = 0; for (int m = 0; m < (int)N; ++m) { if (g[n][m]) mx = max(mx, rec(m)); } return ret = mx + ss[n]; } class GetToTheTop { public: int collectSweets(int K_, vector <int> S_, vector <int> X_, vector <int> Y_, vector <int> L_) { K = K_; X = X_; Y = Y_; L = L_; S = S_; const int size = L.size(); DisjointSet uf(size); for (int i = 0; i < (int)size; ++i) { uf.make(i); } for (int i = 0; i < (int)size; ++i) { for (int j = i + 1; j < (int)size; ++j) { if (Y[i] == Y[j] && reach(i, j)) { uf.join(i, j); } } } fill(&g[0][0], &g[N - 1][N], false); fill(ss, ss + N, 0); for (int i = 0; i < (int)size; ++i) { ss[uf.find(i)] += S[i]; } for (int i = 0; i < (int)size; ++i) { for (int j = 0; j < (int)size; ++j) { if (uf.isSameSet(i, j)) continue; if (Y[i] < Y[j] && reach(i, j)) { int src = uf.find(i); int dst = uf.find(j); g[src][dst] = true; } } } fill(memo, memo + N, -1); int mx = 0; for (int i = 0; i < (int)size; ++i) { if (Y[i] <= K) { mx = max(mx, rec(uf.find(i))); } } return mx; } };