kmjp's blog

競技プログラミング参加記です

KUPC2015 : D - 高橋君の旅行

割とすんなり思いつけた。
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;
	
}

まとめ

シンプルだけど解法が面白い問題でした。