TopCoder SRM 317 Div1 Medium CollectingPayment
問題
n個の仕事があり、i番目の仕事はmoment[i]日目にあり、その報酬がearning[i]である。
報酬は、積算されていき、いつでも好きな日に銀行に振り込ませることができる。
ただし、振込みには一回につき、feeの手数料がかかる。
銀行にふりこまれたお金には、1,8,15,22…日目に利息がつき、
その額はA*(rate/1000.0)である。
その日に振り込まれたお金にも利息がつく。
また、仕事をした当日にその日の報酬を振り込ませることもできる。
365日目に得られる銀行口座の残高の最大値を求めよ。
制約条件
n≦50
1≦moment[i]≦365
earning[i]≦1000
方針
動的計画法による。
dp[i][j]を、i日目までで、現在銀行に振り込まれていない報酬の金額をjとするときの、
銀行口座の残高の最大値とする。
i+1日目には、銀行に給料を振り込ませるか、そのまま積算しておくか選ぶことができ、それぞれの場合についてテーブルを更新することができる。
ソースコード
int n, earn[370]; double dp[2][50001]; class CollectingPayment { public: double maximumProfit(vector <int> earning, vector <int> moment, int fee, int rate) { memset(earn,0,sizeof(earn)); rep(i,earning.size())earn[moment[i]]=earning[i]; rep(j,50001)dp[0][j]=-INF; dp[0][0]=0; int cur=0, next=1; rep(i,365){ rep(j,50001)dp[next][j]=-INF; rep(j,50001)if(dp[cur][j]!=-INF){ double r=i%7==0?1+rate/1000.0:1; dp[next][j+earn[i+1]]=max(dp[next][j+earn[i+1]], dp[cur][j]*r); dp[next][0]=max(dp[next][0], (dp[cur][j]+j+earn[i+1]-fee)*r); } swap(cur,next); } double ans=0; rep(i,50001)ans=max(ans,dp[cur][i]); return ans; } };