割とすんなり思いつけた。
http://kupc2015.contest.atcoder.jp/tasks/kupc2015_d
問題
1~(N+1)のN+1個の町がある。
プレイヤーは初期状態では所持金0で1つ目の町にいる。
プレイヤーは1日ごとにその町にとどまるか次の町に移動できる。
i番目の町にとどまると所持金はB[i]、次の町に移動するとA[i]変化する。
ただし所持金が負になる行動はとれない。
(Bは非負なので、とどまる選択肢は常に可能)
プレイヤーが最適な手段を取った場合、N日後の所持金の最大値を求めよ。
解法
最終的に町xにとどまるとする。
町xに到達する最短日数をf(x)、その際の最大所持金をg(x)とすると、残りN-f(x)日は1~xの町のうちB[y]が最大の町yで稼ぐのがベストで、値はg(x) + (N-f(x))*B[y]となる。
あとは各xに対しf(x), g(x)を順次求めていけば良い。
int N; ll A[101010],B[101010]; ll SB[101010]; ll md[101010],mn[101010]; void solve() { int i,j,k,l,r,x,y; string s; cin>>N; FOR(i,N) cin>>A[i+1]; FOR(i,N) { cin>>B[i+1]; SB[i+1]=max(SB[i],B[i+1]); } ll ma=0; for(i=1;i<=N+1;i++) { if(i>1) { if(mn[i-1]+A[i-1]>=0) { md[i]=md[i-1]+1; mn[i]=mn[i-1]+A[i-1]; } else if(SB[i-1]==0) { break; } else { ll f=-(mn[i-1]+A[i-1]); ll ad = (f+SB[i-1]-1)/SB[i-1]; md[i]=md[i-1]+1+ad; mn[i]=mn[i-1]+A[i-1]+ad*SB[i-1]; } } if(md[i]<=N) ma=max(ma, mn[i] + (N-md[i])*SB[i]); } cout<<ma<<endl; }
まとめ
シンプルだけど解法が面白い問題でした。