柱爷把妹(吃惊高清重制版)
Time Limit: 2000/2000MS (Java/Others) Memory Limit: 125000/125000KB (Java/Others)
某日,喵蛤蛤村,天行廖大师走在咸鱼路上,突然,迎面走来一女子
有言到:
北方有佳人,绝世而独立。
一顾倾人城,再顾倾人国。
闭月羞花怨,沉鱼落雁愁。
貂婵拜月闭冰盘,佳丽忧民叹国残。
回眸一笑百魅生,六宫粉黛无颜色。
解释春风无限恨,沈香亭北倚阑干。
绝代有佳人,幽居在空谷。
君王数载犹尝胆,美色几时能救国?
俊眉修眼,顾盼神飞,文彩精华,见之忘俗。
脸若银盘,眼似水杏,唇不点而红,眉不画而翠。
手如柔荑,肤如凝脂,领如蝤蛴,齿如瓠犀,螓首蛾眉,巧笑倩兮,美目眇兮
咸鱼廖大师的目光已经呆滞,而更让他吃惊的是她的旁边居然是柱爷!
说好的一起单身,柱爷却悄悄的脱了单
当然,把妹柱把妹是需要资金的!,而股市正好是柱爷资金的主要来源地
这是因为柱爷有自己独特的黑科技技巧
柱爷通过交易知道了接下来N天的股市行情,每天的买入/卖出价格为Pi,每天柱爷只能做最多一种操作,当然柱爷也可以什么都不做。
对于每个操作,有一个手续费F,对于买入操作,会在买入操作之前扣除F块钱,而对于卖出操作,则会在柱爷卖出操作执行完后扣除F的手续费.
注意,柱爷初始时有M块钱的本金,柱爷需要保证在任意时刻自己的现金
≥0
现在请问柱爷在N天后最多能有多少钱?
Input
第一行三个整数N,M,F,分别表示一共有N天,本金为M,手续费为F
接下来N行,每行一个整数Pi,代表第i天的交易价格
数据保证:
-
1≤N≤105
-
1≤M≤105
-
1≤F≤105
-
1≤Pi≤2∗105
-
答案≤2∗1018
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;
}