zoukankan      html  css  js  c++  java
  • 寒假第二阶段集训第6天

    F.Cut the Sequence(POJ 3017)

    题意:给你一个长度为n的序列,要求把序列分割成若干个子串,每个子串的数字和不能大于m,每个子串的权值为子串的最大值,求所有子串的最小权值和

    思路:dp[i] 维护从1 - i切割序列可以得到的最小权值和

    又因为子串的的数字和不能超过m,可以得到转移方程是为 dp[i] = min(dp[k] + max(a[k + 1] , ... , a[i]) , dp[i]);同时k应该满足sum[i] - sum[k] <=m ;

    a[k + 1] , ... , a[i] 之间的最大值可以采用单调队列来维护

    #include<cstdio>
    #include<string.h>
    #include<algorithm>
    #include<cmath>
    #include<iostream>
    #include<vector>
    #include<queue>
    #include<set>
    #include<map>
    #include<cctype>
    #include<stack>
    using namespace std;
    typedef long long ll;
    const int maxn = 1e5 + 100;
    const int inf = 0x3f3f3f3f;
    const ll INF = 0x3f3f3f3f3f3f3f3f;
    const int mod = 998244353;
    const double eps = 1e-5;
    ll arr[maxn];
    ll sum[maxn];
    ll dp[maxn];
    struct node
    {
        ll pos;
        ll maxx;
        node(int x, int y)
        {
            pos = x;
            maxx = y;
        }
        node() {}
    }que[maxn];
    
    int main()
    {
        ll n, m;
        
        while (~scanf("%lld %lld", &n, &m))
        {
            sum[0] = 0;
            dp[0] = 0;
            for (int i = 1; i <= n; ++i) scanf("%lld", &arr[i]);
            for (int i = 1; i <= n; ++i)
            {
                sum[i] = sum[i - 1] + arr[i];
                dp[i] = sum[i];
            }
            int head = 1, rear = 1;
            int l = 1;
            for (ll i = 1; i <= n; ++i)
            {
                if (arr[i] > m)
                {
                    printf("-1");
                    return 0;
                }
                while (rear > head&& arr[i] > que[rear - 1].maxx) rear--;
                while (sum[i] - sum[l - 1] > m) ++l;
                que[rear++] = node(i, arr[i]);
                while (rear > head&& sum[i] - sum[que[head].pos - 1] > m) head++;
                dp[i] = min(dp[i], dp[l - 1] + que[head].maxx);
                for (int j = head + 1; j < rear; ++j)
                {
                    dp[i] = min(dp[i], dp[que[j - 1].pos] + que[j].maxx);
                }
            }
            printf("%lld
    ", dp[n]);
        }
    
        return 0;
    }
    View Code

    E.Trade(HDU 3401)

    题意:一个人要买股票,一个人每天可以买入ASi支股票,可以卖出BSi支股票,每支股票的买入价格为APi ,卖出价格为BPi,这个人最多可以持有MaxP支股票,询问T天之后,可以收获的最大利益是多少。一开始这个人持有0支股票,但是金钱无限,每隔W天可以进行一次买入或者卖出

    思路:dp[i][j] 维护第i天持有j支股票的最大收益

    dp[i][j] = max(dp[i - w - 1][k] + (j - k) * AP[i] ,  dp[i - w - 1][k] - (k - j) * AP[i]  , dp[i - w - 1][j] );

    转移方程表示在第i天买入股票,卖出股票,既不买入股票也不卖出股票三种情况中去最小

    以买入股票为例,卖出股票和买入股票同理

    如果第i天买入了股票 dp[i][j] = dp[i - w - 1][k] + (j - k) * AP[i]; 因式分解dp[i][j] + j * AP[i] = dp[i - w - 1][k] + k * AP[i];

    因此对于每个i用单调队列维护dp[i - w - 1][k] + k * AP[i]的最大值

    同时要求每天买入的股票不超过AS[i]支股票

    注:初始化的需要将数组元素初始化为-INF,因为炒股还有有可能会亏钱的,但是最后的结果肯定是大于等于0的,因为如果炒股亏钱的话,那就不要炒股啦。

    #include<cstdio>
    #include<string.h>
    #include<algorithm>
    #include<cmath>
    #include<iostream>
    #include<vector>
    #include<queue>
    #include<set>
    #include<map>
    #include<cctype>
    #include<stack>
    using namespace std;
    typedef long long ll;
    const int maxn = 1e4 + 100;
    const int inf = 0x3f3f3f3f;
    const ll INF = 0x3f3f3f3f3f3f3f3f;
    const int mod = 998244353;
    const double eps = 1e-5;
    int ap[maxn], bp[maxn], as[maxn], bs[maxn];
    int dp[2020][2020];
    
    struct node
    {
        int val;
        int num;
        node(int a, int b)
        {
            val = a;
            num = b;
        }
        node(){}
    }que[maxn];
    
    int main()
    {
        int T;
        scanf("%d", &T);
        while (T--)
        {
            memset(dp, -inf, sizeof dp);
            int n, m,maxx;
            scanf("%d %d %d", &n,&maxx,&m);
            for (int i = 1; i <= n; ++i)
            {
                scanf("%d %d %d %d", &ap[i], &bp[i], &as[i], &bs[i]);
            }
            for (int i = 1; i <= n; ++i)
                for (int j = 0; j <= maxx; ++j)
                    dp[i][j] = -inf;
            for (int i = 1; i <= m + 1; ++i)
                for (int j = 0; j <= as[i]; ++j) dp[i][j] = (-ap[i] * j);
            for (int i = 2; i <= n; ++i)
            {
                for(int j = 0 ; j <= maxx ; ++ j)
                    dp[i][j] = max(dp[i - 1][j], dp[i][j]);
                if (i <= m + 1) continue;
                // 买入 维护一个单调递减队列
                int rear = 1, head = 1;
                for (int j = 0; j <= maxx; ++j)
                {
                    while (rear > head&& que[rear - 1].val < dp[i - m - 1][j] + j * ap[i]) rear--;
                    que[rear++] = node(dp[i - m - 1][j] + j * ap[i], j);
                    while (rear > head&& que[head].num + as[i] < j) head++;
                    dp[i][j] = max(dp[i][j], que[head].val - j * ap[i]);
                }
                rear = 1, head = 1;
                for (int j = maxx; j >= 0; --j)
                {
                    while (rear > head&& que[rear - 1].val < dp[i - m - 1][j] + j * bp[i]) rear--;
                    que[rear++] = node(dp[i - m - 1][j] + j * bp[i], j);
                    while (rear > head&& que[head].num - bs[i] > j) head++;
                    dp[i][j] = max(dp[i][j], que[head].val - j * bp[i]);
                }
            }
            int ans = -inf;
            for (int i = 0; i <= maxx; ++i)
            {
                ans = max(ans, dp[n][i]);
            }
            ans = ans < 0 ? 0 : ans;
            cout << ans << endl;
        }
        
        return 0;
    }
    View Code

     

     

      

  • 相关阅读:
    php生成二维码的几种方式
    CVPR 2013
    面试&笔试---c语言之字符串处理
    逆向知识-汇编寻址方式汇总
    tensorflow中的lstm的state
    图文相关性 flickr数据实验结论_1
    LightGBM中GBDT的实现
    Tensorflow 变量的共享
    Tensorflow 变量的共享
    https://github.com/chenghuige/tensorflow-exp/blob/master/examples/sparse-tensor-classification/
  • 原文地址:https://www.cnblogs.com/DreamACMer/p/12291068.html
Copyright © 2011-2022 走看看