cdoj 1322 柱爷把妹(吃惊高清重制版)

题目传送门

柱爷把妹(吃惊高清重制版)

Time Limit: 2000/2000MS (Java/Others)     Memory Limit: 125000/125000KB (Java/Others)


某日,喵蛤蛤村,天行廖大师走在咸鱼路上,突然,迎面走来一女子

有言到:

北方有佳人,绝世而独立。

一顾倾人城,再顾倾人国。

闭月羞花怨,沉鱼落雁愁。

貂婵拜月闭冰盘,佳丽忧民叹国残。

回眸一笑百魅生,六宫粉黛无颜色。

解释春风无限恨,沈香亭北倚阑干。

绝代有佳人,幽居在空谷。

君王数载犹尝胆,美色几时能救国?

俊眉修眼,顾盼神飞,文彩精华,见之忘俗。

脸若银盘,眼似水杏,唇不点而红,眉不画而翠。

手如柔荑,肤如凝脂,领如蝤蛴,齿如瓠犀,螓首蛾眉,巧笑倩兮,美目眇兮

咸鱼廖大师的目光已经呆滞,而更让他吃惊的是她的旁边居然是柱爷!title

说好的一起单身,柱爷却悄悄的脱了单title

当然,把妹柱把妹是需要资金的!,而股市正好是柱爷资金的主要来源地

这是因为柱爷有自己独特的黑科技技巧

柱爷通过交易知道了接下来N天的股市行情,每天的买入/卖出价格为Pi,每天柱爷只能做最多一种操作,当然柱爷也可以什么都不做。

对于每个操作,有一个手续费F,对于买入操作,会在买入操作之前扣除F块钱,而对于卖出操作,则会在柱爷卖出操作执行完后扣除F的手续费.

注意,柱爷初始时有M块钱的本金,柱爷需要保证在任意时刻自己的现金 0

现在请问柱爷在N天后最多能有多少钱?

Input

第一行三个整数N,MF,分别表示一共有N天,本金为M,手续费为F

接下来N行,每行一个整数Pi,代表第i天的交易价格

数据保证:

  • 1N105  

  • 1M105  

  • 1F105   

  • 1Pi2105  

  • 21018 

Output

输出仅一行,表示柱爷 N N天后能拥有的最多现金

Sample input and output

Sample Input Sample Output
3 10000 1
4000
4004
4002
10006
3 10000 100000
4000
4004
4002
10000

Hint

对于样例 1 1,柱爷会在第一天买入 2 2股,在第 2 2天卖出 2 2股最优

这样柱爷能赚最多的钱(就能更好的把妹了)



最近在做动规的专题练习,就做到了这道题。此题很容易想到O(n^2的算法,定义dp[i]为第i天,已经做出决策的最大收益,状态转移方程为dp[i] = max(dp[i-1],(dp[k] - F) / p[k + 1] * p[i] + (dp[k] - F) % p[k] - F),但对于题中数据范围,这显然无能为力。然而股票市场波动不定,价格并无单调性,此方程也无法用斜率优化,我们就要另寻出路。

首先此题数据为1e5,显然可以用O(nlogn) 或 O(n) 过O(nlongn)的做法为cdq分治(然并不会)。O(n)的做法为动规。首先,如果没有手续费,那么此题就是比较接近理想收入问题。如果存在a < b < c , p[a] < p[b] < p[c],那么我们可以得到a->b, b->c 等价于a -> c。(证明很显然)。现在有F,怎么办,加了以后再减就好。这样我们就可以实现O(1)的转移。先用O(n)进行预处理,再进行O(n)的dp。

见了代码就比较清晰思路。

#include <bits/stdc++.h>
using namespace std;

const int Maxn = 100010;
typedef long long LL;
int p[Maxn], nxt[Maxn], Stack[Maxn];
LL dp[Maxn][2];

void SelfMax(LL &a, const LL &b) { if (a < b) a = b; }

int main() {
	int N, M, F;
	scanf("%d%d%d", &N, &M, &F);
	for (int i = 1; i <= N; ++i) scanf("%d", p + i);
	int top = 0; Stack[top] = N;
	for (int i = N; i; --i) {
		while (top && p[i] >= p[Stack[top]]) --top;
		if (top) nxt[i] = Stack[top];
		else nxt[i] = i;
		Stack[++top] = i;
	}
	memset(dp, 128, sizeof dp);
	dp[1][0] = M;  LL tmp, ans = 0;
	for (int i = 1; i <= N; ++i) {
		SelfMax(ans, dp[i][0]); SelfMax(ans, dp[i][1]);
		SelfMax(dp[i + 1][0], max(dp[i][0], dp[i][1]));
		SelfMax(dp[nxt[i]][0], max(dp[i][0], dp[i][1]));
		tmp = dp[i][0] - F; 
		if (tmp > 0 && nxt[i] > i) 
			SelfMax(dp[nxt[i]][1], tmp / p[i] * p[nxt[i]] + tmp % p[i] - F);
		tmp = dp[i][1] + F;
		if (tmp > 0 && nxt[i] > i) 
			SelfMax(dp[nxt[i]][1], tmp / p[i] * p[nxt[i]] + tmp % p[i] - F);
	}
	cout << ans << endl;
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值