andre_joy

导航

hdu 3401

地址:http://acm.hdu.edu.cn/showproblem.php?pid=3401

题意:炒股……规定每天最多买进多少,卖出多少,并且每次炒股后隔w天才能再次炒股,问最大收益。

mark:首先想到最朴素的dp。dp[i][j]代表第i天有j股会带来最大收益。

    则dp[i][j]  = max(dp[i-1][j], dp[r][k]-(j-k)ap[i], dp[r][k]+(k-j)bp[i]);  复杂度是O(T*T*Maxp*Maxp)。

   首先想到第一步优化,前面式子r范围是0~i-w-1,怎么优化呢,因为dp[i][j]至少为dp[i-1][j],那么dp[i-w-1][k] >= dp[...][k]恒成立(...指r的范围内的数)

   故dp[i][j]  = max(dp[i-1][j], dp[i-w-1][k]-(j-k)ap[i], dp[i-w-1][k]+(k-j)bp[i]); 复杂度是O(T*Maxp*Maxp)。还是很大。

   接下来就是单调队列的作用了,单调队列需要理解,就是维护一个两头出,一头进的队列,具体实现不好说。复杂度可以优化到O(T*Maxp)

代码:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

const int M = 2000+10;
const int N = -10000000;
int n,maxp,w;
int dp[M][M];
int q1[M],q2[M];
int ap[M],bp[M],as[M],bs[M];

int max(int a, int b, int c)
{
    int m = a > b ? a: b;
    return m > c ? m : c;
}

int min(int a, int b) {return a < b ? a : b;}

void solve()
{
    int max1,max2,min1,fr1,fr2,la1,la2;
    int i,j,k;
    for(i = 1; i <= w+1; i++)
    {
        min1 = min(as[i], maxp);
        for(j = 0; j <= min1; j++)
            dp[i][j] = -ap[i]*j;
    }
    for(i = 2; i <= n; i++)
    {
        for(j = 0; j <= maxp; j++)
            dp[i][j] = max(dp[i][j], dp[i-1][j], N);
        if(i <= w+1) continue;
        fr1 = la1 = 0;
        fr2 = la2 = 0;
        q2[la2++] = 0;
        min1 = min(bs[i], maxp);
        for(k = 1; k <= min1; k++)
        {
            while(dp[i-w-1][q2[la2-1]]+q2[la2-1]*bp[i] <= dp[i-w-1][k]+k*bp[i])
            {
                la2--;
                if(fr2 == la2) break;
            }
            q2[la2++] = k;
        }
        for(j = 0; j <= maxp; j++)
        {
            if(j+bs[i] <= maxp)
            {
                while(dp[i-w-1][j+bs[i]]+(j+bs[i])*bp[i] >= dp[i-w-1][q2[la2-1]]+q2[la2-1]*bp[i])
                {
                    la2--;
                    if(fr2 == la2) break;
                }
                q2[la2++] = j+bs[i];
            }
            if(q2[fr2] == j) fr2++;
            if(fr2 == la2) max2 = N;
            else max2 = dp[i-w-1][q2[fr2]]+q2[fr2]*bp[i]-j*bp[i];
            if(j)
            {
                if(fr1 == la1) q1[la1++] = j-1;
                else
                {
                    while(dp[i-w-1][j-1]+(j-1)*ap[i] >= dp[i-w-1][q1[la1-1]]+q1[la1-1]*ap[i])
                    {
                        la1--;
                        if(fr1 == la1) break;
                    }
                    q1[la1++] = j-1;
                    while(q1[la1-1]-q1[fr1] >= as[i]) fr1++;
                }
                max1 = dp[i-w-1][q1[fr1]]+q1[fr1]*ap[i]-j*ap[i];
            }
            else max1 = N;
            dp[i][j] = max(dp[i][j], max1, max2);
        }
    }
    max1 = 0;
    for(i = 0; i <= maxp; i++)
        if(max1 < dp[n][i]) max1 = dp[n][i];
    printf("%d\n", max1);
}

int main()
{
//    freopen("in.txt", "r", stdin);
//    freopen("out.txt", "w", stdout);
    int t;
    int i,j,k;
    scanf("%d", &t);
    while(t-- && scanf("%d%d%d", &n, &maxp, &w))
    {
        for(i = 1; i <= n; i++)
            scanf("%d%d%d%d", ap+i, bp+i, as+i, bs+i);
        for(i = 0; i <= n; i++)
            for(j = 0; j <= maxp; j++)
                dp[i][j] = N;
        solve();
    }
    return 0;
}

posted on 2012-08-06 16:17  andre_joy  阅读(241)  评论(0编辑  收藏  举报