TopCoder SRM 390 Div1 Medium PaintingBoards
問題
板が一列に並んでいて、それぞれの長さはboardLength[i]である。
何人かがこの板に色を塗る。
それぞれの人が一秒間に塗る板の長さはpainterSpeed[i]である。
それぞれの人は、一枚または連続する何枚かの板を担当することができる。
全ての板の色を塗り終えるまでにかかる最短の時間を求めよ。
制約条件
boardLengthの要素の数≦50
painterSpeedの要素の数≦15
boardLength[i]≦10000
painterSpeed[i]≦10000
方針
二分探索+ビットDP.
かなり珍しいタイプの問題な気がする。
かける時間Tを一つ決めた後にビットDPにより全ての板が塗れるかどうかを判定する。
dp[mask]を、maskであらわされる人を使って塗れる板の最大の枚数とする。
状態遷移は、
「今までに塗られた板の枚数から、次の人が時間T以内で塗れる板の枚数」を考える必要があるが、
これはgreedyに計算できる。
Editorialの解法では、二分探索でTを決めるたびに、
i番の人がj枚目から塗り始めたときに何枚目までいけるかnext[i][j]を毎回前計算している。
なので自分もそれにならった。
ソースコード
int dp[1<<15]; int next[15][51]; class PaintingBoards { public: double minimalTime(vector <int> boardLength, vector <int> painterSpeed) { int n=boardLength.size(), m=painterSpeed.size(); double lo=0,hi=INF,mid; rep(it,100){ mid=(lo+hi)/2; rep(i,m)rep(j,n+1){ int k=j,len=0; while(k<n&&len+boardLength[k]<mid*painterSpeed[i]+EPS) len+=boardLength[k++]; next[i][j]=k; } rep(i,1<<m)dp[i]=0; rep(i,1<<m)rep(j,m)if(!(i&1<<j)) dp[i^1<<j]=max(dp[i^1<<j],next[j][dp[i]]); if(dp[(1<<m)-1]==n)hi=mid; else lo=mid; } return lo; } };