/* Gen 1: Multiple orderings + improved width search Based on reference.cpp with: - 4 ordering strategies (ascending min dim, descending area, descending max dim, random) - Each width tries all orderings (time permitting) - Better width candidate generation */ #include using namespace std; struct T{int w,h;vector> c;vector lo,hi;int r,f,minx,miny;}; struct P{int id,k;vector> b;vector t;int minW=1e9,minH=1e9,minA=1e9;}; struct Pl{int idx,ti,x,y;}; struct R{long long A;int W,H;vector pl;}; struct RNG{unsigned long long s;RNG(unsigned long long x){s=x?x:1;}inline unsigned long long nxt(){s^=s<<7;s^=s>>9;return s;}inline int rint(int n){return (int)(nxt()%n);}inline bool coin(){return nxt()&1;}}; static inline pair rotp(pair p,int r){if(r==0)return p; if(r==1)return make_pair(-p.second,p.first); if(r==2)return make_pair(-p.first,-p.second); return make_pair(p.second,-p.first);} int main(){ ios::sync_with_stdio(false); cin.tie(nullptr); int n; if(!(cin>>n)) return 0; vector

ps(n); long long S=0; for(int i=0;i>k; ps[i].id=i+1; ps[i].k=k; ps[i].b.resize(k); for(int j=0;j>x>>y; ps[i].b[j]={x,y};} S+=k; } for(int i=0;i seen; seen.reserve(32); for(int rf=0;rf<2;rf++){ vector> src=p.b; if(rf){for(auto &q:src) q.first=-q.first;} for(int r=0;r<4;r++){ vector> v=src; for(auto &q:v) q=rotp(q,r); int minx=INT_MAX,miny=INT_MAX,maxx=INT_MIN,maxy=INT_MIN; for(auto &q:v){minx=min(minx,q.first);miny=min(miny,q.second);maxx=max(maxx,q.first);maxy=max(maxy,q.second);} vector> v2=v; for(auto &q:v2){q.first-=minx;q.second-=miny;} sort(v2.begin(),v2.end()); string key; key.reserve(v2.size()*8); for(auto &q:v2){key.append(to_string(q.first));key.push_back(',');key.append(to_string(q.second));key.push_back(';');} if(seen.insert(key).second){ T t; t.w=maxx-minx+1; t.h=maxy-miny+1; t.c=v2; t.r=r; t.f=rf; t.minx=minx; t.miny=miny; t.lo.assign(t.w,INT_MAX); t.hi.assign(t.w,INT_MIN); for(auto &q:v2){int x=q.first,y=q.second; if(t.lo[x]>y) t.lo[x]=y; if(t.hi[x] idx(n); iota(idx.begin(),idx.end(),0); unsigned long long seed=((unsigned long long)chrono::high_resolution_clock::now().time_since_epoch().count()) ^ (S<<1) ^ (unsigned long long)(n*1469598103934665603ULL); RNG rng(seed); // Multiple ordering strategies auto ord_asc_mindim = [&]() { vector res = idx; stable_sort(res.begin(), res.end(), [&](int a, int b) { int da = min(ps[a].minW, ps[a].minH); int db = min(ps[b].minW, ps[b].minH); if (da != db) return da < db; if (ps[a].k != ps[b].k) return ps[a].k < ps[b].k; return ps[a].id > ps[b].id; }); return res; }; auto ord_desc_area = [&]() { vector res = idx; stable_sort(res.begin(), res.end(), [&](int a, int b) { if (ps[a].k != ps[b].k) return ps[a].k > ps[b].k; int da = min(ps[a].minW, ps[a].minH); int db = min(ps[b].minW, ps[b].minH); if (da != db) return da > db; return ps[a].id < ps[b].id; }); return res; }; auto ord_desc_maxdim = [&]() { vector res = idx; stable_sort(res.begin(), res.end(), [&](int a, int b) { int da = max(ps[a].minW, ps[a].minH); int db = max(ps[b].minW, ps[b].minH); if (da != db) return da > db; if (ps[a].k != ps[b].k) return ps[a].k > ps[b].k; return ps[a].id < ps[b].id; }); return res; }; auto ord_desc_bbox = [&]() { vector res = idx; stable_sort(res.begin(), res.end(), [&](int a, int b) { if (ps[a].minA != ps[b].minA) return ps[a].minA > ps[b].minA; if (ps[a].k != ps[b].k) return ps[a].k > ps[b].k; return ps[a].id < ps[b].id; }); return res; }; auto ord_random = [&]() { vector res = idx; for(int i=n-1;i>0;i--){ int j=rng.rint(i+1); swap(res[i],res[j]); } return res; }; // Perturb a given ordering by making random swaps auto ord_perturb = [&](const vector& base_ord, int nswaps) { vector res = base_ord; for(int i=0;i res = idx; stable_sort(res.begin(), res.end(), [&](int a, int b) { int va=(int)ps[a].t.size(), vb=(int)ps[b].t.size(); if(va!=vb) return vaps[b].k; return ps[a].id& o0,RNG &rng,bool randtie){ vector h(W,-1); long long g=-1; vector pl; pl.reserve(o0.size()); vector o=o0; int t=0,nm=(int)o.size(); bool big=S>7000; int maxBound=max(1,n/4); int expLIM=min(maxBound,(int)(350000/max(1LL,S-3500))); int dynLIM=big?expLIM:maxBound; auto tStart=chrono::steady_clock::now(); auto batchStart=tStart; long long TLms=big?1900:LLONG_MAX/4; int stepCnt=0; while(tW) continue; int Rpos=W-tsh.w+1; for(int x0=0;x0y0) y0=v;} } int nhbuf[32]; int l=-1; long long dsum=0; for(int j=0;jl) l=nh; } for(int j=0;j0) dsum+=inc; } long long dr=0; if(x0>0){ long long old=llabs((long long)h[x0]-h[x0-1]); long long nw=llabs((long long)nhbuf[0]-h[x0-1]); dr+=nw-old; } for(int j=0;j(now-tStart).count(); auto batch=chrono::duration(now-batchStart).count(); double remT=max(0.0,TLms-elapsed); int remSteps=max(1,nm-t); double budget=remT*5.0/remSteps; if(batch(now-tStart).count(); auto batch=chrono::duration(now-batchStart).count(); double remT=max(0.0,TLms-elapsed); int remSteps=max(1,nm-t); double budget=remT*5.0/remSteps; if(batchmaxX) maxX=x;} } int Wused=0; if(maxX>=0){ vector used(maxX+1,false); for(auto &pp:pl){auto &t=ps[pp.idx].t[pp.ti]; for(auto &q:t.c){used[pp.x+q.first]=true;}} for(int x=0;x<=maxX;x++) if(used[x]) Wused++; } int Wfinal=max(0,Wused); long long A=1LL*H*max(1,Wfinal); return R{A,max(1,Wfinal),H,move(pl)}; }; // Gap-filling pack for small inputs - tries positions below skyline using bitmap auto pack_gap=[&](int W,const vector& o0,RNG &rng,bool randtie) -> R { int maxHg=(int)(S/max(1,W)+W+50); vector> grid(W, vector(maxHg, false)); vector h(W,-1); long long g=-1; vector pl; pl.reserve(o0.size()); vector o=o0; int t2=0,nm=(int)o.size(); bool big2=(S>7000); int maxBound=max(1,n/4); int expLIM2=min(maxBound,(int)(350000/max(1LL,S-3500))); int dynLIM=big2?expLIM2:maxBound; bool gapEnabled=true; auto gpTStart=chrono::steady_clock::now(); auto gpBatchStart=gpTStart; long long gpTLms=big2?1800:LLONG_MAX/4; int gpStepCnt=0; while(t2W) continue; int Rpos=W-tsh.w+1; for(int x0=0;x0y0) y0=v;} } // Also try gap positions (scan up to 10 rows below skyline) int gapY=-1; if(gapEnabled && y0>0){ int sd=min(y0,3); // Only check 3 rows below skyline for(int gy=max(0,y0-sd);gy=maxHg||grid[gx][gcy]){ok=false;break;} } if(ok){gapY=gy;break;} } } // Evaluate both positions for(int pass=0;pass<(gapY>=0?2:1);pass++){ int yy=(pass==0)?y0:gapY; int nhbuf[32]; int l=-1; long long dsum=0; for(int j=0;jl) l=nh; } for(int j=0;j0) dsum+=inc;} long long dr=0; if(x0>0){dr+=llabs((long long)nhbuf[0]-h[x0-1])-llabs((long long)h[x0]-h[x0-1]);} for(int j=0;j=0&&gx=0&&gy(gpNow-gpTStart).count(); auto gpBatch=chrono::duration(gpNow-gpBatchStart).count(); double gpRemT=max(0.0,(double)gpTLms-gpElapsed); int gpRemSteps=max(1,nm-t2); double gpBudget=gpRemT*5.0/gpRemSteps; if(gpBatchmaxX) maxX=x;}} int Wused=0; if(maxX>=0){vector used(maxX+1,false); for(auto &pp:pl){auto &t=ps[pp.idx].t[pp.ti]; for(auto &q:t.c){used[pp.x+q.first]=true;}} for(int x=0;x<=maxX;x++) if(used[x]) Wused++;} int Wfinal=max(0,Wused); long long A=1LL*H*max(1,Wfinal); return R{A,max(1,Wfinal),H,move(pl)}; }; int minW=0; for(auto &p:ps) minW=max(minW,p.minW); // Improved width estimation double factor; if (S < 1000) factor = 0.4; else if (S < 3000) factor = 0.5; else if (S < 10000) factor = 0.27; else if (S < 30000) factor = 0.08; else factor = 0.01; int base = max(minW, (int)floor(sqrt((double)S * factor))); vector Ws; { unordered_set used; used.reserve(512); auto addW=[&](int w){if(w(minW,(S+base-1)/base)); for(int m=2;m<=6;m++){addW(base*m/3); addW((int)max(minW,S/((base*m/3)?(base*m/3):1)));} // Add sqrt(S) based widths for more square-like rectangles int sqrtS = max(minW, (int)floor(sqrt((double)S))); addW(sqrtS); addW(sqrtS+1); addW(sqrtS-1); addW(sqrtS*2/3); addW(sqrtS/2); sort(Ws.begin(),Ws.end(),[&](int a,int b){int da=abs(a-base),db=abs(b-base); if(da!=db) return da> base_orders; base_orders.push_back(ord_asc_mindim()); if(!useGapPacker){ base_orders.push_back(ord_desc_area()); base_orders.push_back(ord_desc_maxdim()); base_orders.push_back(ord_desc_bbox()); base_orders.push_back(ord_flexibility()); } auto doPack = [&](int W, const vector& order, RNG& rng, bool randtie) -> R { if(useGapPacker) return pack_gap(W, order, rng, randtie); return pack(W, order, rng, randtie); }; // Track best ordering index per width for perturbation int bestOrderIdx = 0; for(int wi=0;wi<(int)Ws.size();wi++){ auto now=chrono::steady_clock::now(); double used_time=chrono::duration(now-t0).count(); if(used_time+avg*1.3>TL) break; int W=Ws[wi]; // Try each base ordering for(int oi=0;oi<(int)base_orders.size();oi++){ now=chrono::steady_clock::now(); double used2=chrono::duration(now-t0).count(); if(used2+avg*1.15>TL) break; bool randtie=(oi>=1); auto t1=chrono::steady_clock::now(); R r=doPack(W,base_orders[oi],rng,randtie); auto t2=chrono::steady_clock::now(); double dt=chrono::duration(t2-t1).count(); cnt++; avg=(avg*(cnt-1)+dt)/cnt; if(!hasBestmine || r.A(now-t0).count(); if(used2+avg*1.15>TL) break; auto t1=chrono::steady_clock::now(); vector order; if(ri < 2) order = ord_perturb(base_orders[bestOrderIdx], nswaps); else order = ord_random(); R r=doPack(W,order,rng,true); auto t2=chrono::steady_clock::now(); double dt=chrono::duration(t2-t1).count(); cnt++; avg=(avg*(cnt-1)+dt)/cnt; if(!hasBestmine || r.AmaxX) maxX=x;} } vector mapx(maxX+1,-1); if(maxX>=0){ vector used(maxX+1,false); for(auto &p:bestR.pl){ auto &t=ps[p.idx].t[p.ti]; for(auto &q:t.c){used[p.x+q.first]=true;} } int cur=0; for(int x=0;x<=maxX;x++) if(used[x]) mapx[x]=cur++; } vector> ans(n,{0,0,0,0}); for(auto &p:bestR.pl){ auto &t=ps[p.idx].t[p.ti]; int bx = (mapx.empty()?p.x:mapx[p.x]); int Xi = bx - t.minx; int Yi = p.y - t.miny; int Ri = (4 - (t.r%4) + 4) % 4; int Fi = t.f; ans[p.idx]={Xi,Yi,Ri,Fi}; } cout<