diff --git a/algorithmic/problems/0/examples/gpt5.cpp b/algorithmic/problems/0/examples/gpt5.cpp index da4d1dc3e..38a729126 100644 --- a/algorithmic/problems/0/examples/gpt5.cpp +++ b/algorithmic/problems/0/examples/gpt5.cpp @@ -1,271 +1,363 @@ #include using namespace std; -struct Cell { int x, y; }; -struct Transform { int R, F; }; // reflect (y-axis) then rotate R*90° CW -struct Oriented { - vector pts; // normalized: minx=miny=0 +struct FastScanner { + static const int BUFSIZE = 1<<20; + int idx, size; + char buf[BUFSIZE]; + FastScanner(): idx(0), size(0) {} + inline char getChar() { + if (idx >= size) { + size = (int)fread(buf, 1, BUFSIZE, stdin); + idx = 0; + if (size == 0) return 0; + } + return buf[idx++]; + } + template + bool nextInt(T &out) { + char c; T sign = 1, val = 0; + c = getChar(); + if (!c) return false; + while (c!='-' && (c<'0'||c>'9')) { + c = getChar(); + if (!c) return false; + } + if (c=='-') { sign = -1; c = getChar(); } + for (; c>='0' && c<='9'; c=getChar()) val = val*10 + (c - '0'); + out = val * sign; + return true; + } +}; + +struct VecHash { + size_t operator()(const vector& v) const noexcept { + uint64_t h = 1469598103934665603ULL; + for (int x : v) { + h ^= (uint64_t)(uint32_t)x + 0x9e3779b97f4a7c15ULL + (h<<6) + (h>>2); + h *= 1099511628211ULL; + } + return (size_t)h; + } +}; + +struct Orientation { int w, h; - int offx, offy; // = -minx, -miny (to undo normalization for output) - Transform tf; + unsigned char R, F; }; + struct Piece { - int id; - vector base; - vector variants; - int area; + int k; + vector> cells; // original + vector oris; // unique orientations + int minW; + int hmin; + int w_at_hmin; + int areaMin; }; -static inline uint64_t pack_xy(int x,int y){ - return (uint64_t(uint32_t(x))<<32) | uint32_t(y); -} -static inline pair apply_transform(int x,int y,int F,int R){ +struct Placement { + int X, Y; + unsigned char R, F; +}; + +struct Result { + int W, H; + long long area; + vector P; // size n +}; + +static inline pair transform_point(int x, int y, int F, int R) { if (F) x = -x; - switch (R & 3){ - case 0: return { x, y}; - case 1: return { y, -x}; // 90 CW - case 2: return {-x, -y}; // 180 - default:return {-y, x}; // 270 CW + int nx=x, ny=y; + switch (R & 3) { + case 0: nx = x; ny = y; break; + case 1: nx = y; ny = -x; break; + case 2: nx = -x; ny = -y; break; + case 3: nx = -y; ny = x; break; } + return {nx, ny}; } -static Oriented make_oriented(const vector& base,int F,int R){ - vector t; t.reserve(base.size()); - int minx=INT_MAX,miny=INT_MAX,maxx=INT_MIN,maxy=INT_MIN; - for (auto &c: base){ - auto [tx,ty]=apply_transform(c.x,c.y,F,R); - minx=min(minx,tx); miny=min(miny,ty); - maxx=max(maxx,tx); maxy=max(maxy,ty); - t.push_back({tx,ty}); + +int main() { + ios::sync_with_stdio(false); + cin.tie(nullptr); + + FastScanner fs; + int n; + if (!fs.nextInt(n)) { + return 0; } - // normalization - for (auto &c: t){ c.x -= minx; c.y -= miny; } - int W = maxx-minx+1, H = maxy-miny+1; - sort(t.begin(), t.end(), [](const Cell&a,const Cell&b){ - if (a.y!=b.y) return a.y cand; cand.reserve(8); - for (int F=0;F<=1;++F) for (int R=0;R<4;++R) - cand.push_back(make_oriented(P.base,F,R)); - // dedup - vector uniq; - for (auto &o: cand){ - bool dup=false; - for (auto &u: uniq){ - if (u.w==o.w && u.h==o.h && u.pts.size()==o.pts.size()){ - bool same=true; - for (size_t i=0;i pieces(n); + long long totalCells = 0; + for (int i = 0; i < n; ++i) { + int k; fs.nextInt(k); + pieces[i].k = k; + pieces[i].cells.resize(k); + totalCells += k; + for (int j = 0; j < k; ++j) { + int x, y; fs.nextInt(x); fs.nextInt(y); + pieces[i].cells[j] = {x, y}; } - if (!dup) uniq.push_back(o); } - P.variants.swap(uniq); -} - -struct Placement { int X=0,Y=0,R=0,F=0; int w=0,h=0; int vi=-1; }; // vi = variant index used -struct PackedSolution { int W=0,H=0; vector place; }; -struct World { - int W, Hlimit; // square side S; W==Hlimit==S - vector height; - unordered_set occ; - int maxH=0; - - World(int S=1){ clear(S); } - void clear(int S){ W=S; Hlimit=S; height.assign(W,0); occ.clear(); maxH=0; } + // Precompute unique orientations for each piece + for (int i = 0; i < n; ++i) { + auto &pc = pieces[i]; + unordered_set, VecHash> seen; + pc.oris.clear(); + for (int F = 0; F <= 1; ++F) { + for (int R = 0; R < 4; ++R) { + int minx = INT_MAX, miny = INT_MAX, maxx = INT_MIN, maxy = INT_MIN; + vector> pts; pts.reserve(pc.k); + pts.clear(); + for (auto &p : pc.cells) { + auto q = transform_point(p.first, p.second, F, R); + pts.push_back(q); + if (q.first < minx) minx = q.first; + if (q.second < miny) miny = q.second; + if (q.first > maxx) maxx = q.first; + if (q.second > maxy) maxy = q.second; + } + // Normalize so minx=0, miny=0 + int shiftx = -minx, shifty = -miny; + vector> norm; norm.reserve(pc.k); + for (auto &q : pts) norm.push_back({q.first + shiftx, q.second + shifty}); + sort(norm.begin(), norm.end()); + vector key; key.reserve(pc.k * 2); + for (auto &q : norm) { key.push_back(q.first); key.push_back(q.second); } - inline int shelfY(int x,int w) const { - int y=0; for (int i=0;i W) return false; - if (Y + o.h > Hlimit) return false; // enforce square height cap - for (auto &c: o.pts){ - int gx=X+c.x, gy=Y+c.y; - if (occ.find(pack_xy(gx,gy))!=occ.end()) return false; + if (seen.insert(key).second) { + Orientation o; + o.w = maxx - minx + 1; + o.h = maxy - miny + 1; + o.R = (unsigned char)R; + o.F = (unsigned char)F; + pc.oris.push_back(o); + } + } } - return true; - } - inline void do_place(const Oriented& o,int X,int Y){ - for (auto &c: o.pts){ - int gx=X+c.x, gy=Y+c.y; - occ.insert(pack_xy(gx,gy)); - height[gx]=max(height[gx], gy+1); - if (height[gx]>maxH) maxH=height[gx]; + if (pc.oris.empty()) { + // Should not happen, but ensure at least identity + Orientation o; o.w = 1; o.h = 1; o.R = 0; o.F = 0; + pc.oris.push_back(o); + } + // Metrics + pc.minW = INT_MAX; + pc.hmin = INT_MAX; + pc.w_at_hmin = INT_MAX; + pc.areaMin = INT_MAX; + for (auto &o : pc.oris) { + pc.minW = min(pc.minW, o.w); + if (o.h < pc.hmin) { + pc.hmin = o.h; + pc.w_at_hmin = o.w; + } else if (o.h == pc.hmin) { + pc.w_at_hmin = min(pc.w_at_hmin, o.w); + } + pc.areaMin = min(pc.areaMin, o.w * o.h); } } -}; -int main(){ - ios::sync_with_stdio(false); - cin.tie(nullptr); + // Orders + vector idx(n); + iota(idx.begin(), idx.end(), 0); - int n; if(!(cin>>n)) return 0; - vector P(n); - long long totalCells=0; - for (int i=0;i>k; - P[i].base.resize(k); - for (int j=0;j>x>>y; P[i].base[j]={x,y}; } - P[i].area=k; totalCells+=k; - build_variants(P[i]); + vector> orders; + { + auto ord = idx; + stable_sort(ord.begin(), ord.end(), [&](int a, int b) { + if (pieces[a].hmin != pieces[b].hmin) return pieces[a].hmin > pieces[b].hmin; + if (pieces[a].areaMin != pieces[b].areaMin) return pieces[a].areaMin > pieces[b].areaMin; + if (pieces[a].minW != pieces[b].minW) return pieces[a].minW > pieces[b].minW; + return a < b; + }); + orders.push_back(ord); } - - // Place larger / less flexible first - vector order(n); iota(order.begin(), order.end(), 0); - sort(order.begin(), order.end(), [&](int a,int b){ - if (P[a].area!=P[b].area) return P[a].area>P[b].area; - return P[a].variants.size() pieces[b].areaMin; + if (pieces[a].hmin != pieces[b].hmin) return pieces[a].hmin > pieces[b].hmin; + if (pieces[a].minW != pieces[b].minW) return pieces[a].minW > pieces[b].minW; + return a < b; + }); + orders.push_back(ord); + } + { + auto ord = idx; + stable_sort(ord.begin(), ord.end(), [&](int a, int b) { + if (pieces[a].minW != pieces[b].minW) return pieces[a].minW > pieces[b].minW; + if (pieces[a].hmin != pieces[b].hmin) return pieces[a].hmin > pieces[b].hmin; + if (pieces[a].areaMin != pieces[b].areaMin) return pieces[a].areaMin > pieces[b].areaMin; + return a < b; + }); + orders.push_back(ord); } - int S0 = max(S_area, S_geom); - // Generate candidate square sizes; grow if needed - vector sides = { - S0, - max(S0, (int)ceil(1.05*S0)), - max(S0, (int)ceil(1.15*S0)), - max(S0, (int)ceil(0.95*S0)) - }; - sort(sides.begin(), sides.end()); - sides.erase(unique(sides.begin(), sides.end()), sides.end()); + int W_minGlobal = 1; + for (int i = 0; i < n; ++i) W_minGlobal = max(W_minGlobal, pieces[i].minW); + int baseW = (int)floor(sqrt((double)max(1LL, totalCells))); + baseW = max(baseW, W_minGlobal); - auto better = [](const PackedSolution& A, const PackedSolution& B){ - if (B.W==0) return true; - long long aA=1LL*A.W*A.H, aB=1LL*B.W*B.H; - if (aA!=aB) return aA widthCands; + auto addW = [&](int w) { + if (w < W_minGlobal) w = W_minGlobal; + if (w <= 0) w = W_minGlobal; + widthCands.push_back(w); }; + addW(baseW); + addW(W_minGlobal); + for (int d = -5; d <= 8; ++d) { + double factor = pow(1.12, d); + int w = (int)llround(baseW * factor); + addW(w); + } + for (int i = 1; i <= 5; ++i) addW(baseW + i); + for (int i = 1; i <= 5; ++i) addW(baseW - i); + addW((int)(baseW * 1.5)); + addW((int)(baseW * 0.85)); + addW((int)(baseW * 1.25)); + addW((int)(baseW * 2.0)); - PackedSolution best; best.W=0; best.H=INT_MAX; - - auto try_with_side = [&](int S)->optional{ - World world(S); - world.occ.reserve((size_t)totalCells*2 + 1024); - vector place(n); - - for (int idx=0; idx vord(piece.variants.size()); - iota(vord.begin(), vord.end(), 0); - sort(vord.begin(), vord.end(), [&](int a,int b){ - const auto&A=piece.variants[a], &B=piece.variants[b]; - if (A.h!=B.h) return A.hB.w; - return A.pts.size()>B.pts.size(); - }); + // Dedup and clamp + sort(widthCands.begin(), widthCands.end()); + widthCands.erase(unique(widthCands.begin(), widthCands.end()), widthCands.end()); - int bestVi=-1, bestX=-1, bestY=INT_MAX; + // Time limit handling + auto tstart = chrono::high_resolution_clock::now(); + const double TIME_LIMIT = 1.85; - for (int vi: vord){ - const auto &o = piece.variants[vi]; - if (o.w > world.W || o.h > world.Hlimit) continue; + Result bestRes; + bestRes.area = (1LL<<62); + bestRes.W = bestRes.H = 0; + bestRes.P.resize(n); - // x scan (try both coarse step and right align) - int step = max(1, o.w/2); - for (int x=0; x + o.w <= world.W; x += step){ - int y = world.shelfY(x, o.w); - if (y + o.h > world.Hlimit) continue; // square cap - if (y > bestY) continue; - if (!world.can_place(o, x, y)) continue; - bestY=y; bestX=x; bestVi=vi; + auto packWithWidth = [&](int W, const vector& order, Result &out) { + int y0 = 0, shelf_h = 0, x = 0; + vector placements(n); + for (int id : order) { + const auto &pc = pieces[id]; + while (true) { + int rem = W - x; + int bestIdx = -1; + int bestH = INT_MAX; + int bestW = -1; // choose larger width on tie to fill space + int bestArea = INT_MAX; + for (int oi = 0; oi < (int)pc.oris.size(); ++oi) { + const auto &o = pc.oris[oi]; + if (o.w <= rem) { + if (o.h < bestH) { + bestH = o.h; + bestW = o.w; + bestArea = o.w * o.h; + bestIdx = oi; + } else if (o.h == bestH) { + if (o.w > bestW) { + bestW = o.w; + bestArea = o.w * o.h; + bestIdx = oi; + } else if (o.w == bestW) { + int area = o.w * o.h; + if (area < bestArea) { + bestArea = area; + bestIdx = oi; + } + } + } + } } - int xr = world.W - o.w; - if (xr>=0){ - int y = world.shelfY(xr, o.w); - if (y + o.h <= world.Hlimit && y <= bestY && world.can_place(o, xr, y)){ - bestY=y; bestX=xr; bestVi=vi; + if (bestIdx == -1) { + if (x == 0) { + // cannot fit even in empty shelf - should not happen if W >= minW + // fallback: pick orientation with minimal width and place anyway by increasing W (but we can't). So just choose minimal width and proceed. + int mw = INT_MAX, mhi = -1; + for (int oi = 0; oi < (int)pc.oris.size(); ++oi) { + const auto &o = pc.oris[oi]; + if (o.w < mw) { mw = o.w; mhi = oi; } + } + if (mhi == -1) mhi = 0; + const auto &o = pc.oris[mhi]; + placements[id] = {x, y0, o.R, o.F}; + x += o.w; + shelf_h = max(shelf_h, o.h); + break; + } else { + // Close shelf, start new + y0 += shelf_h; + shelf_h = 0; + x = 0; + continue; } + } else { + const auto &o = pc.oris[bestIdx]; + placements[id] = {x, y0, o.R, o.F}; + x += o.w; + if (o.h > shelf_h) shelf_h = o.h; + break; } } - - if (bestVi<0) return {}; // fail for this S - - const auto &o = piece.variants[bestVi]; - world.do_place(o, bestX, bestY); - place[i] = {bestX, bestY, o.tf.R, o.tf.F, o.w, o.h, bestVi}; } - - // success with this S - PackedSolution cand; - cand.W = S; - cand.H = S; // enforce square - cand.place.resize(n); - for (int i=0;i(now - tstart).count(); + if (elapsed > TIME_LIMIT) break; - // If none worked, escalate S until it does (guaranteed cap: vertical stack height) - if (best.W==0){ - // Safe upper bound: stack piece heights of a chosen variant each - int maxW=1, sumH=0; - for (auto &p: P){ - int wmin=INT_MAX, hmin=INT_MAX; - for (auto &o: p.variants){ - wmin = min(wmin, o.w); - hmin = min(hmin, o.h); + Result cur; + cur.P.resize(n); + int W = widthCands[wi]; + packWithWidth(W, order, cur); + // choose best + if (cur.area < bestRes.area + || (cur.area == bestRes.area && (cur.H < bestRes.H || (cur.H == bestRes.H && cur.W < bestRes.W)))) { + bestRes = cur; } - maxW = max(maxW, wmin); - sumH += hmin; } - int S = max({S0, maxW, sumH}); // square that trivially fits vertical stack - // grow linearly from S0 to S (usually hits long before) - for (int s = S0; s <= S; ++s){ - if (auto sol = try_with_side(s)){ best = *sol; break; } - } - // If still nothing (extremely unlikely), force a trivial square stack at side S - if (best.W==0){ - int y=0; - vector pl(n); - // Use each piece's first variant - for (int i=0;i(now - tstart).count(); + if (elapsed > TIME_LIMIT) break; + } + + // Fallback if somehow not set + if (bestRes.area >= (1LL<<62)) { + // Simple fallback: single column using minimal width orientation, W = W_minGlobal + int W = W_minGlobal; + vector placements(n); + int y = 0; + for (int i = 0; i < n; ++i) { + int bestIdx = 0; + int bestH = INT_MAX, bestW = INT_MAX; + for (int oi = 0; oi < (int)pieces[i].oris.size(); ++oi) { + auto &o = pieces[i].oris[oi]; + if (o.w <= W) { + if (o.h < bestH || (o.h == bestH && o.w < bestW)) { + bestH = o.h; bestW = o.w; bestIdx = oi; + } + } } - int Sforce = max({S, y, maxW}); - best.W = best.H = Sforce; - best.place = move(pl); + auto &o = pieces[i].oris[bestIdx]; + placements[i] = {0, y, o.R, o.F}; + y += o.h; } + bestRes.W = W; bestRes.H = y; bestRes.area = 1LL*W*y; bestRes.P = placements; } - // ---- OUTPUT with offset compensation ---- - cout << best.W << " " << best.H << "\n"; - for (int i=0;i