なんだこれ…。
https://community.topcoder.com/stat?c=problem_statement&pm=17222&rd=18894
問題
6列・R行からなる飛行機の座席群がある。
各座席の番号は、row-major orderで0-indexで振られている。
各列両端の座席は窓側、3列目・4列目の座席は通路側、2列目・5列目の座席は中央側と呼ぶことにする。
今、飛行機にいくつかの団体が順に搭乗してくる。
各団体は以下のように座席につく。
- 残座席が団体の人数以下の場合、そこで終了。
- 団体が1名の場合、窓側→通路側→中央側の順で、空き席があれば番号が最小のところに座る。
- 団体が2名以上の場合、全員が同じ行に座れるなら、そのうち左から詰めて座る。
- 全員が同じ行に座れないなら、各自1名の団体が複数あるかのように座る。
団体の人数が与えられたとき、各人の座席を答えよ。
解法
1名の団体向けに、各列における空き行のsetを保持しつつ、2名以上の団体向けに、n席以上の空き席がある行のsetを管理しよう。
int avail[101010]; set<int> S[7]; set<int> C[7]; class OccupiedAirplane { public: long long seat(int R, vector <int> groups, int seed) { int i,j; FOR(i,7) S[i].clear(),C[i].clear(); int lef=R*6; FOR(i,R) { avail[i]=(1<<6)-1; for(j=1;j<=6;j++) S[j].insert(i); FOR(j,3) C[j].insert(i); } ll state=seed; FOR(i,600001) { state = (state * 1103515245 + 12345)%(1LL<<31); int g = ((state >> 10)%6) + 1; groups.push_back(g); } ll num=1; ll ret=0; FORR(g,groups) { vector<int> G; if(g>lef) break; lef-=g; if(S[g].size()) { G.push_back(g); } else { while(g--) G.push_back(1); } FORR(a,G) { int row; if(a==1) { vector<int> O={0,2,1}; FORR(i,O) if(C[i].size()) { row=*C[i].begin(); j=i; if((avail[row]&(1<<j))==0) j=5-j; avail[row]^=1<<j; ret+=num*(row*6+j); num++; break; } } else { row=*S[a].begin(); FOR(i,6) if(a&&(avail[row]&(1<<i))) { a--; avail[row]^=1<<i; ret+=num*(row*6+i); num++; } } FOR(j,7) S[j].erase(row),C[j].erase(row); for(j=1;j<=6;j++) if(__builtin_popcount(avail[row])>=j) S[j].insert(row); FOR(j,6) if(avail[row]&(1<<j)) C[min(j,5-j)].insert(row); } } return ret; } }
まとめ
面倒なだけで面白みを感じない問題で、かつ凡ミスで落としたのしょうもなさ過ぎてしんどい。