您的位置:首页 > 其它

洛谷Oj-低价购买-最长下降子序列 +最佳方案数统计

2017-09-17 08:58 197 查看
问题描述:

“低价购买”这条建议是在奶牛股票市场取得成功的一半规则。要想被认为是伟大的投资者,你必须遵循以下的问题建议:“低价购买;再低价购买”。每次你购买一支股票,你必须用低于你上次购买它的价格购买它。买的次数越多越好!你的目标是在遵循以上建议的前提下,求你最多能购买股票的次数。你将被给出一段时间内一支股票每天的出售价(2^16范围内的正整数),你可以选择在哪些天购买这支股票。每次购买都必须遵循“低价购买;再低价购买”的原则。写一个程序计算最大购买次数。

这里是某支股票的价格清单:

日期 1 2 3 4 5 6 7 8 9 10 11 12

价格 68 69 54 64 68 64 70 67 78 62 98 87

最优秀的投资者可以购买最多4次股票,可行方案中的一种是:

日期 2 5 6 10

价格 69 68 64 62

AC代码:

int a[5010],dp[5010],sum[5010];//dp[i]代表以第i个元素为结尾的下降子序列的最大长度,sum[i]代表下降子序列的长度为dp[i]的序列的个数
int main()
{
int n;
cin >> n;
for(int i = 1; i <= n; ++i)
{
scanf("%d",&a[i]);//输入
dp[i] = 1;//初始化
sum[i] = 1;//初始化
}
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= i - 1; ++j)
{
if(a[j] > a[i])//下降
{
if(dp[j] + 1 > dp[i])//如果dp[j] + 1大于当前答案dp[i],就可以转移
{
sum[i] = 0;//清0
dp[i] = dp[j] + 1;//状态转移方程
}
if(dp[j] + 1 == dp[i])
sum[i] += sum[j];//注意+1是错误的,要加上j的方案数
}
if(a[j] == a[i] && dp[j] == dp[i])//判重的语句,这说明两个序列是完全相同的
sum[j] = 0;//清0
}
int ans = -inf;
for(int i = 1; i <= n; ++i)
ans = max(ans,dp[i]);//找出最长的
int cnt = 0;
for(int i = 1; i <= n; ++i)
if(dp[i] == ans)
cnt += sum[i];//计算所有长度为ans的序列的方案数
cout << ans << " " << cnt << endl;
return 0;
}


解决方法:

加法原理:如果一件事有k个选择,每个选择有a[i]种方案,则一共有Σa[i]种方案。

这道题的难点在于如何判断重复的情况。如果不需要判断重复,只需要sum[i] += sum[j]即可。

既然要判断重复,不妨举个例子:6 5 4 4,有两个最长下降子序列6 5 4 和 6 5 4,二者是相同的情况。

不妨设j < i,a[i] = 4, a[j] = 4。发现特点就是a[i] == a[j]且dp[i] == dp[j]。因为有最长这个条件的保证,6 5 4序列中除去4和6 5 4序列中除去4剩下的部分6 5是完全相同的。

去重只需要将sum[j](或sum[i])赋值为0即可,因为dp方程是由前向后推的,若i和j能继续转移,则必被重复计算,所以sum[i]和sum[j]只能保留一个。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: