【中山市选2010】股票投资

Description:

很多人都梦想成为股神,但是股票投资是需要一定基本功的。熟知股票买卖的规则就是其中一件很重要的事情。顾名思义,股票的单位是“股”;但是实际上,在公开交易市场,股票交易的单位是“手”,1手股票等于100股股票。另外,和其他商业买卖一样,股票交易是要纳税的。股票交易的税有两种,一种是交易税,一种是印花税。假设当前股价是P,你要买或者卖X手股票,那么你需要付出或者得到的钱是G=P*100*X。与此同时,无论买或者买,你都必须支付交易税和印花税。印花税有一个固定税率T,例如0.001,则你所需支付的印花税为G*T。交易税类似印花税,也有一个固定税率S1,但同时也有一个最低税额S2,这意味着,如果 GS1<S2 ,则你依然需要支付S2的税款,即你需要缴纳的税款为 max(G*S1,S2)。
好了,懂得这个规则,现在你可以小试牛刀了。不过,股票市场更需要的是投资策略。问题来了,假设某个时刻T0,你拥有C元现金;接下来的n秒钟,T1,T2,…,Tn,你都清楚知道某一只股票的价格Pi。在这n秒钟,你都可以任意买入或者卖出或者持有这只股票,当然,无论什么时候,你必须保证你的现金不能出现负数,你也不可能卖出比你持有数量更多的股票。同时T,S1,S2也是已知的。在这样的情况下,第n秒结束
后,你可以拥有的现金最多会是多少?

题解:

只要你能想到贪心,那这题就是个小学生动态规划题。

首先股票一定是一买一卖这样子搞下去。

并且要买就买最多的,要卖就卖完。

那么可以设:
f,g,h 分别表示当前没有股票的情况下最多有多少钱,有股票最多能有多少股,股票最多的情况下剩余钱最多是多少。

这样枚举当前干什么来转移:
1.啥也不干。
2.卖完前面买的股票。
3.花所有的前买股票。

至于能买、卖多少股票不好确定可以直接二分。

复杂度:O(n log n)

Code:

#include 
#define ld long double
#define fo(i, x, y) for(int i = x; i <= y; i ++)
#define max(a, b) ((a) > (b) ? (a) : (b))
using namespace std;

const int N = 3e5 + 5;

ld f[N], c[N]; int g[N];
int n, tt; ld p, C, s1, s2, T;

int main() {
    freopen("stock.in", "r", stdin);
    freopen("stock.out", "w", stdout);
    for(scanf("%d", &tt); tt; tt --) {
        scanf("%Lf %Lf %Lf %Lf", &C, &s1, &s2, &T);
        scanf("%d", &n);
        f[0] = c[0] = C; g[0] = 0;
        fo(i, 1, n) {
            scanf("%Lf", &p);
            for(int l = 0, r = 1e9; l <= r; ) {
                int m = l + r >> 1;
                ld G = p * 100 * m;
                ld s = G * T + max(G * s1, s2);
                if(G + s <= f[i - 1]) {
                    g[i] = m; c[i] = f[i - 1] - G - s;
                    l = m + 1;
                } else r = m - 1;
            }
            if(g[i - 1] > g[i] || g[i - 1] == g[i] && c[i - 1] > c[i])
                g[i] = g[i - 1], c[i] = c[i - 1];
            ld G = p * 100 * g[i - 1];
            ld s = G * T + max(G * s1, s2);
            f[i] = max(f[i - 1], c[i - 1] + G - s);
        }
        printf("%.3Lf\n", f[n]);
    }
}

你可能感兴趣的:(动态规划,贪心)