SRM539 DIV2 -Level2

問題
①数字の配列が2つ与えられる。
 それぞれの番号は、岩が入るBOXの最小の数と最大の数を表わす。
②あなたは岩を無数に持っており、選んだBOXに最小の数以上、
 最大の数まで岩を入れることができる。
③このとき、岩を9001個以上入れた時に表わすことのできる
 岩の個数の場合の数を返す。

解き方
問題文を最初ミスリーディングしてしまったのですが、
「9001個以上入れることのできる場合の数」ではなく、
「表わすことのできる岩の個数の場合の数」になります。

最初にこのまま全探索しても手掛かりがないため、
全てのBOXの選び方はO(2^15=10^3*32)で選ぶことができるため
選んだBOXについて考える。

そうすることで最小の岩の数と最大の岩の数がわかるため、
9001以上の表わせる岩の個数がわかる。

ただし表わせる岩の個数を配列に保存しようとすると
次に、岩の数は10^6とかなり大きいため、
O(10^6*10^3*32)で計算できない。

そこで、全て配列に保存するのではなく
範囲を保存することを考える。
始点の岩の数の配列を+1とし、終点の次の配列をー1とすることで、
+のときはその間の数は存在することとなる。

この処理を全て行っていくと、
配列の数を最初から足していったとき+1以上のときはその数は存在することとなる。

Challengeポイント
配列(ループ)の数を10^7*2だとエラーになってしまいました。
10^6*1.6だと通ったので、
10^7*2以上にならないことがChallengeのポイントになりそうです。

またケアレスミスをしてしまいましたが
ビット列計算をするときは&&ではなく&になります。

コード
class Over9000Rocks {

public: int countPossibilities(vector<int> lowerBound, vector<int> upperBound) {
int n=lowerBound.size(),ans=0;
vector<int> check(16000000,0);

for(int select=1;select<(1<<n);select++){
int upper=0,lower=0;
for(int j=0;j<n;j++){
if(select&1<<j){
lower+=lowerBound[j];
upper+=upperBound[j];
}
}
check[lower]++;
check[upper+1]--;
}

int parity=0;
FORE(i,0,(int)check.size()){
parity+=check[i];
if(i>9000 && parity>0)ans++;
}

return ans;
}

};

このエントリーをはてなブックマークに追加