Mediumのツメが甘くまたレートダウン。
https://community.topcoder.com/stat?c=problem_statement&pm=15296
問題
残り体力がHである敵を倒すターン制ゲームを考える。
1ターンあたり1回攻撃でき、初回の攻撃では、Aだけダメージを与えられる。
以後、ダメージを与えるたびに以後の攻撃のダメージはAのL%だけ増加する(複利ではなく、毎回A*L/100だけ増加)。
ここで、ゲーム中1回だけ魔法を唱えることができる。
(魔法を唱えるのも1ターン消費し、そのターンは攻撃できない)
魔法を唱えると、以後Dターンの間、与えるダメージが本来の計算式の5倍になる。
攻撃と魔法の最適手を取る場合、最小何ターンで敵の体力を0以下にできるか。
解法
ターン数が多いほどダメージが多いので、二分探索で最小ターンを求めよう。
まず、魔法については1ターンで敵を倒せる場合以外は、必ずどこかで唱えた方が良い。
Lは最大100%なので、1ターン魔法を唱えることでダメージ倍加のチャンスを逃してもお釣りがくる。
さらに言えば、後半ほど与ダメージが増えるので、終盤Dターンにダメージが5倍になるようにしよう。
class FightMonsterDiv1 { public: ll H,A,A2,D; __int128_t dam(__int128_t v) { if(v==1) return A; v--; __int128_t ret=v*A; ret+=A2*v*(v-1)/2; __int128_t du=min((__int128_t)D,v); __int128_t cur=A+(v-1)*A2; ret+=4*cur*du; ret-=A2*du*(du-1)/2*4; return ret; } long long fightTime(long long hp, long long attack, int level, long long duration) { H=hp; A=attack; A2=A*level/100; D=duration; ll ret=1LL<<40; for(int i=39;i>=0;i--) if(dam(ret-(1LL<<i))>=H) ret-=1LL<<i; return ret; } }
まとめ
問題文に対しサンプルが不親切でわかりにくい…。