zoukankan      html  css  js  c++  java
  • 【bzoj1742】[Usaco2005 nov]Grazing on the Run 边跑边吃草 区间dp

    题目描述

    John养了一只叫Joseph的奶牛。一次她去放牛,来到一个非常长的一片地,上面有N块地方长了茂盛的草。我们可以认为草地是一个数轴上的一些点。Joseph看到这些草非常兴奋,它想把它们全部吃光。于是它开始左右行走,吃草。John和Joseph开始的时候站在p位置。Joseph的移动速度是一个单位时间一个单位距离。不幸的是,草如果长时间不吃,就会腐败。我们定义一堆草的腐败值是从Joseph开始吃草到吃到这堆草的总时间。Joseph可不想吃太腐败的草,它请John帮它安排一个路线,使得它吃完所有的草后,总腐败值最小。John的数学很烂,她不知道该怎样
    做,你能帮她么?

    输入

    * Line 1 : Two space-separated integers: N and L. N<=1000
    * Lines 2..N+1: Each line contains a single integer giving the position P of a clump (1 <= P <= 1,000,000).

    输出

    * Line 1: A single integer: the minimum total staleness Bessie can achieve while eating all the clumps.

    样例输入

    4 10
    1
    9
    11
    19

    样例输出

    44


    题解

    区间dp,膜拜popoqqq

    因为路过的草一定吃,所以吃的草一定是一段区间。

    用f[i][k]表示吃完从i开始连续的k堆草,且此时在左侧的最小腐败值,

    用g[i][k]表示吃完从i开始连续的k堆草,且此时在右侧的最小腐败值。

    这样我们发现腐败值很难求,并且无法保证最优。

    所以我们可以先计算出每段时间所有草增加的腐败值,这样既能保证dp的成立,又方便计算。

    状态转移方程应该很容易由f/g[i/i+1][k-1]推出来。

    由于空间限制,需要用到滚动数组黑科技。

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    long long f[1001][2] , g[1001][2] , p[1001];
    int main()
    {
        int n , i , j , k , cl = 0 , cr = 0;
        long long m;
        scanf("%d%lld" , &n , &m);
        for(i = 1 ; i <= n ; i ++ )
            scanf("%lld" , &p[i]);
        sort(p + 1 , p + n + 1);
        for(i = 1 ; i <= n ; i ++ )
        {
            if(p[i] <= m)
                cl = i;
            if(!cr && p[i] > m)
                cr = i;
        }
        memset(f , 0x3f , sizeof(f));
        memset(g , 0x3f , sizeof(g));
        if(cl) f[cl][1] = g[cl][1] = n * (m - p[cl]);
        if(cr) f[cr][1] = g[cr][1] = n * (p[cr] - m);
        for(k = 2 ; k <= n ; k ++ )
        {
            for(i = 1 ; i + k - 1 <= n ; i ++ )
            {
                j = i + k - 1;
                f[i][k & 1] = min(f[i + 1][~k & 1] + (n - k + 1) * (p[i + 1] - p[i]) , g[i + 1][~k & 1] + (n - k + 1) * (p[j] - p[i]));
                g[i][k & 1] = min(g[i][~k & 1] + (n - k + 1) * (p[j] - p[j - 1]) , f[i][~k & 1] + (n - k + 1) * (p[j] - p[i]));
            }
        }
        printf("%lld
    " , min(f[1][n & 1] , g[1][n & 1]));
        return 0;
    }
  • 相关阅读:
    Python学习笔记捌——面向对象高级编程
    Python学习笔记五,函数及其参数
    Python学习笔记四,dict和set
    Python学习笔记三,数组list和tuple
    Python学习笔记一,输入输出
    Linux 环境下自动化测试工具,Redhat dogtail的安装
    Testlink接口使用方法-python语言远程调用
    Python入门学习之input()与raw_input()的区别
    从客户端(&)中检测到有潜在危险的 Request.Path 值解决方案
    树莓派嵌入式开发第一课笔记
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/6396881.html
Copyright © 2011-2022 走看看