Best Financing
Time Limit: 20000/10000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 590 Accepted Submission(s): 196
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:
收益数值,保留小数点后两位,四舍五入。
Sample Input
2 1 2 1 10000 1 100 5 50 200 10 2 2 1 10000 5 20000 1 5 6 5 9 7
Sample Output
Case #1: 1000.00 Case #2: 2700.00
题解:这一题建模后最终变成了DAG上的动态规划。
因为投资没有上限,于是,每个单位的钱都是独立的,于是独立考虑每个单位的钱。
每个单位的钱,取那个单位的钱,到来的时间,走到最后的最大收益,乘以earnings。这样就能得出earnings块投资的最大收益。
求每个单位的钱可以取得的最大值,DP可解(每个时间点用对应的边连起来,可以得到一个DAG)。
然后对所有的n个收入,分别求最大值,加起来便是答案。
注意数据需要离散化。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long ll;
const int maxn=10000+10;
int date[maxn],earning[maxn],start[maxn],finish[maxn],rate[maxn];
int Hash[maxn*10],num[maxn],d[maxn],head[maxn];
int tot;
int cnt;
struct Edge
{
int to,v,next;
}edge[maxn];
void addedge(int u,int v,int w)
{
edge[cnt].to=v,edge[cnt].v=w,edge[cnt].next=head[u],head[u]=cnt++;
}
void init()
{
memset(head,-1,sizeof(head));
memset(Hash,0,sizeof(Hash));
memset(d,0,sizeof(d));
cnt=0;
}
int main()
{
int cas;
scanf("%d",&cas);
for(int k=1;k<=cas;k++)
{
int n,m;
scanf("%d%d",&n,&m);
init();
tot=0;
for(int i=0;i<n;i++)
scanf("%d%d",&date[i],&earning[i]),num[tot++]=date[i];
for(int i=0;i<m;i++)
scanf("%d%d%d",&start[i],&finish[i],&rate[i]),num[tot++]=start[i],num[tot++]=finish[i];
sort(num,num+tot);
tot=unique(num,num+tot)-num;
for(int i=0;i<tot;i++)
Hash[num[i]]=i;
for(int i=1;i<tot;i++) addedge(i-1,i,0);
for(int i=0;i<m;i++) addedge(Hash[start[i]],Hash[finish[i]],rate[i]);
for(int u=tot-1;u>=0;u--)
{
for(int i=head[u];i!=-1;i=edge[i].next)
{
int v=edge[i].to,cost=edge[i].v;
d[u]=max(d[u],d[v]+cost);
}
}
ll ans=0;
for(int i=0;i<n;i++)
{
ans+=d[Hash[date[i]]]*(ll)earning[i];
}
printf("Case #%d:\n",k);
double res=1.0*ans/100;
printf("%.2lf\n",res);
}
return 0;
}