HDU 4833 Best Financing(DP)(2014年百度之星程序设计大赛 - 初赛(第二轮))
Problem Description
小A想通过合理投资银行理财产品达到收益最大化。已知小A在未来一段时间中的收入情况,描述为两个长度为n的整数数组dates和earnings,表示在第dates[i]天小A收入earnings[i]元(0<=i<n)。银行推出的理财产品均为周期和收益确定的,可描述为长度为m的三个整数数组start、finish和interest_rates, 若购买理财产品i(0<=i<m),需要在第start[i]天投入本金,在第finish[i]天可取回本金和收益,在这期间本金和收益都无法取回,收益为本金*interest_rates[i]/100.0。当天取得的收入或理财产品到期取回的本金当天即可购买理财产品(注意:不考虑复利,即购买理财产品获得的收益不能用于购买后续的理财产品)。假定闲置的钱没有其他收益,如活期收益等,所有收益只能通过购买这些理财产品获得。求小A可以获得的最大收益。
限制条件:
1<=n<=2500
1<=m<=2500
对于任意i(0<=i<n),1<=dates[i]<=100000,1<=earnings[i]<=100000, dates中无重复元素。
对于任意i(0<=i<m),1<=start[i]<finish[i]<=100000, 1<=interest_rates[i]<=100。
限制条件:
1<=n<=2500
1<=m<=2500
对于任意i(0<=i<n),1<=dates[i]<=100000,1<=earnings[i]<=100000, dates中无重复元素。
对于任意i(0<=i<m),1<=start[i]<finish[i]<=100000, 1<=interest_rates[i]<=100。
Input
第一行为T (T<=200),表示输入数据组数。
每组数据格式如下:
第一行是n m
之后连续n行,每行为两个以空格分隔的整数,依次为date和earning
之后连续m行,每行为三个以空格分隔的整数,依次为start, finish和interest_rate
每组数据格式如下:
第一行是n m
之后连续n行,每行为两个以空格分隔的整数,依次为date和earning
之后连续m行,每行为三个以空格分隔的整数,依次为start, finish和interest_rate
Output
对第i组数据,i从1开始计,输出
Case #i:
收益数值,保留小数点后两位,四舍五入。
Case #i:
收益数值,保留小数点后两位,四舍五入。
题目大意:略。
思路:注意到题目有讲到,收益是不能用来投资的,所以窝们只需要关心投资的钱能赚多少钱就好。
然后,因为投资没有上限,于是,每个单位的钱都是独立的,于是独立考虑每个单位的钱。
每个单位的钱,取那个单位的钱,到来的时间,走到最后的最大收益,乘以earnings。这样就能得出earnings块投资的最大收益。
求每个单位的钱可以取得的最大值,DP可解(每个时间点用对应的边连起来,可以得到一个DAG)。
然后对所有的n个收入,分别求最大值,加起来便是答案。
PS:每个时间点开始一个单位钱可以获得的最大收益可以一开始就求出来……之前脑抽每次都求一遍……还好我离散化了没有TLE……后来发现别人时间都比我快10倍我才想起来QAQ……
代码(265MS):
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <iostream> 5 #include <queue> 6 using namespace std; 7 typedef long long LL; 8 9 const int MAXV = 10010; 10 const int MAXE = MAXV * 4; 11 12 int head[MAXV], ecnt; 13 int to[MAXE], next[MAXE], cost[MAXE]; 14 15 void init(int n) { 16 memset(head, -1, n * sizeof(int)); 17 ecnt = 0; 18 } 19 20 void add_edge(int u, int v, int c) { 21 to[ecnt] = v; cost[ecnt] = c; next[ecnt] = head[u]; head[u] = ecnt++; 22 } 23 24 int dis[MAXV]; 25 26 void solve(int n) { 27 memset(dis, 0, n * sizeof(int)); 28 for(int u = n - 1; u >= 0; --u) { 29 for(int p = head[u]; ~p; p = next[p]) { 30 int &v = to[p]; 31 dis[u] = max(dis[u], dis[v] + cost[p]); 32 } 33 } 34 } 35 36 int dates[MAXV], earning[MAXV]; 37 int start[MAXV], finish[MAXV], rates[MAXV]; 38 int tmp[MAXV], tcnt; 39 int T, n, m; 40 41 int hash(int x) { 42 return lower_bound(tmp, tmp + tcnt, x) - tmp; 43 } 44 45 int main() { 46 scanf("%d", &T); 47 for(int t = 1; t <= T; ++t) { 48 scanf("%d%d", &n, &m); 49 for(int i = 0; i < n; ++i) scanf("%d%d", &dates[i], &earning[i]); 50 for(int i = 0; i < m; ++i) scanf("%d%d%d", &start[i], &finish[i], &rates[i]); 51 52 tcnt = 0; 53 for(int i = 0; i < n; ++i) tmp[tcnt++] = dates[i]; 54 for(int i = 0; i < m; ++i) 55 tmp[tcnt++] = start[i], tmp[tcnt++] = finish[i]; 56 sort(tmp, tmp + tcnt); 57 tcnt = unique(tmp, tmp + tcnt) - tmp; 58 59 init(tcnt); 60 for(int i = 1; i < tcnt; ++i) add_edge(i - 1, i, 0); 61 for(int i = 0; i < m; ++i) add_edge(hash(start[i]), hash(finish[i]), rates[i]); 62 63 solve(tcnt); 64 LL ans = 0; 65 for(int i = 0; i < n; ++i) { 66 ans += LL(earning[i]) * dis[hash(dates[i])]; 67 } 68 69 printf("Case #%d:\n", t); 70 printf("%I64d.%02I64d\n", ans / 100, ans % 100); 71 } 72 }