题解

46 条题解

  • 0
    @ 2009-09-01 20:59:43

    我蒟蒻,不知道单调队列是什么……

    这题我是这样想的:

    用F表示跳到第i个可得到的最多能量,a表示如果不考虑跳跃时消耗的能量,跳到第i个可得到的最多能量(即1~i能量球的和+原始能量),g[i]表示跳到第i个的最少损失(跳跃造成的损失)。显然我们可以得出f[i]:=a[i]-g[i],故我们求f[i]的过程可以转化为求g[i]的过程。显然g[i]:=min(g[j])+i*100(f[j]>=i*100),我猜想g是一个升序的序列,所以每次找j不必一个一个地枚举,只需找出满足f[j]>=i*100中最小的j即可,于是就诞生了O(N)算法。

    请教大牛下,我的猜想和算法对吗?

  • 0
    @ 2009-08-29 16:47:46

    呵呵,第175人AC

    首先谢谢zztDANTE的题解,让我茅塞顿开,谢谢阿!!!

    其次,可以加一个很小的优化,就是所有数据用实数存储,对每个高度获得的能量,(即每个读入数据)都除以100,这样后面就不用再动不动就*100或/100了,少了很多运算

  • 0
    @ 2009-08-24 19:54:05

    为啥我的这么慢?

    编译通过...

    ├ 测试数据 01:答案正确... 0ms

    ├ 测试数据 02:答案正确... 0ms

    ├ 测试数据 03:答案正确... 0ms

    ├ 测试数据 04:答案正确... 0ms

    ├ 测试数据 05:答案正确... 0ms

    ├ 测试数据 06:答案正确... 0ms

    ├ 测试数据 07:答案正确... 0ms

    ├ 测试数据 08:答案正确... 572ms

    ├ 测试数据 09:答案正确... 556ms

    ├ 测试数据 10:答案正确... 556ms

    ---|---|---|---|---|---|---|---|-

    Accepted 有效得分:100 有效耗时:1684ms

  • 0
    @ 2009-08-23 13:39:09

    20行不到AC……

    单调队列果然强大……

    Orz

  • 0
    @ 2009-08-20 19:08:35

    Orz 单调队列!!

  • 0
    @ 2009-08-19 21:11:14

    ├ 测试数据 01:答案正确... 0ms

    ├ 测试数据 02:答案正确... 0ms

    ├ 测试数据 03:答案正确... 0ms

    ├ 测试数据 04:答案正确... 0ms

    ├ 测试数据 05:答案正确... 0ms

    ├ 测试数据 06:答案正确... 0ms

    ├ 测试数据 07:答案正确... 0ms

    ├ 测试数据 08:答案正确... 197ms

    ├ 测试数据 09:答案正确... 166ms

    ├ 测试数据 10:答案正确... 197ms

    ---|---|---|---|---|---|---|---|-

    Accepted 有效得分:100 有效耗时:560ms

    对于本题,光了解解题思想是不够的,要加以转化,并加以实现(否则就不止百把个AC了)

    显然,本题要求O(n)算法,而本题的DP是O(n^2)的,所以需要优化。

    不妨设:f[h]为跳到h高度后可以得到的最大能量,注意到:

    若f[h]是由f[hi]演变而来(即获得hi的最大能量后,再跳到h),那么,不存在h>=hj>=hi,使从f[hj]演变而来的f[h]大于由f[hi]演变而来的f[h]

    证明:令sum[n]表示从1至n的能量总和

    f=f[hi]+sum[n]-sum[hi]-h*100

    f=f[hj]+sum[n]-sum[hj]-h*100

    显然f>f

    换句话说:对于h,最优解总是来自可以到达h的最小高度

    从这个指导思想出发,我有了以下的解法:

    f[n]为跳到n高度后可以得到的最大能量

    g[n]为可以跳到n高度的最小高度

    fillchar g[i]=-1

    预处理 i=0

    for i:=1 to n do

    begin

    f[i]:=f[g[i]]+sum[i]-sum[g[i]]-i*100;

    k:=f[i] div 100;

    ! !

    for j:=!i+1 to k! do

    if g[j]=-1 then

    g[j]:=i

    ! !

    end;

    当我写到这里的时候,我得了0分.......

    仔细想想,有什么地方错了呢?

    首先,对于k,若f[i]很大,k是很容易大于n的,这时其实我们已经找到了到达n高度的最小高度,可以直接输出结果(当然,k=n时也表示找到了这样的高度)。另外,若有一个g[n]-1那么它前面的高度应该都已经赋过值了(而且比当前值小),所以应该从k点往前赋值,并且遇到g[n]-1时跳出

    修改了! !中间的部分,得到AC的程序

    fillchar(g,sizeof(g),$ff);

    g[0]:=0;

    k:=f[0] div 100;

    for i:=1 to k do

    g[i]:=0;

    for i:=1 to n do

    begin

    f[i]:=f[g[i]]+sum[i]-sum[g[i]]-i*100;

    k:=f[i] div 100;

    if k>=n then begin

    f[n]:=f[i]+sum[n]-sum[i]-n*100;

    writeln(f[n]);exit;

    end;

    for j:=k downto i+1 do

    if g[j]=-1 then

    g[j]:=i

    else break;

    end;

  • 0
    @ 2009-11-02 20:41:58

    DP+单调队列

    f[i]:表示前i次跳跃能吃的最大能量值

    sum[i]:表示前i次跳跃的能量值

    q[l..r]:表示前i-1次跳跃结束后的最大值

    (每次对第i个数进行调整,l取min{l | f[q[l]]>=i*100})

    此时,f[i]:=f[q[l]]+sum[i]-sum[q[l]]-i*100;

    Ans:=f[n]

    成功得解决了时间复杂度的问题 O(NlogN)

  • 0
    @ 2009-08-18 18:30:57

    g[i] 表示第i次是从g[i]跳过来的。

    f[i] 为跳到i的所剩的最大能量。

    每次从i-1次跳到的点开始枚举。

    如果(f[j]>=i*100)跳的到i就附值。

    f[i]:=f[j]+v[i]-v[j]-i*100;

    g[i]:=j;

  • 0
    @ 2009-08-18 15:52:38

    单调队列果然是个好东西,从这个题学了很多

    ORZ教主

  • 0
    @ 2009-08-17 17:52:13

    我用的是二分,但我不知道对不对,考试时一个都没过,不知道是我写错了,还是算法本身有问题

  • 0
    @ 2009-08-17 17:09:21

    队列如何维护啊

    orz

  • 0
    @ 2009-08-17 14:04:08

    编译通过...

    ├ 测试数据 01:答案正确... 0ms

    ├ 测试数据 02:答案正确... 0ms

    ├ 测试数据 03:答案正确... 0ms

    ├ 测试数据 04:答案正确... 0ms

    ├ 测试数据 05:答案正确... 0ms

    ├ 测试数据 06:答案正确... 0ms

    ├ 测试数据 07:答案正确... 0ms

    ├ 测试数据 08:答案正确... 166ms

    ├ 测试数据 09:答案正确... 166ms

    ├ 测试数据 10:答案正确... 181ms

    ---|---|---|---|---|---|---|---|-

    Accepted 有效得分:100 有效耗时:513ms

    二十几行代码!!

    但是我的跟 zgx大牛的有点不同

    方程是一样的

    但是我是将f加入队尾

    inc(op);

    t[op]:=i-1;

    运气不错 AC了``

  • 0
    @ 2009-08-17 14:03:13

    编译通过...

    ├ 测试数据 01:答案正确... 0ms

    ├ 测试数据 02:答案正确... 0ms

    ├ 测试数据 03:答案正确... 0ms

    ├ 测试数据 04:答案正确... 0ms

    ├ 测试数据 05:答案正确... 0ms

    ├ 测试数据 06:答案正确... 0ms

    ├ 测试数据 07:答案正确... 0ms

    ├ 测试数据 08:答案正确... 228ms

    ├ 测试数据 09:答案正确... 244ms

    ├ 测试数据 10:答案正确... 166ms

    ---|---|---|---|---|---|---|---|-

    Accepted 有效得分:100 有效耗时:638ms

    第66个AC!

    算法:

    方程是 F=F[J]+SUM-SUM[J]-I*100 ;

    用一个队列优:

    每次从队头开始找一个j可以到达i,并把j之前的都删掉,

    如果f[i]>f[队尾的那个],那么i就入队。

    最后答案是f[n].

    算法证明在下面这位。

  • 0
    @ 2009-08-17 09:53:38

    编译通过...

    ├ 测试数据 01:答案正确... 0ms

    ├ 测试数据 02:答案正确... 0ms

    ├ 测试数据 03:答案正确... 0ms

    ├ 测试数据 04:答案正确... 0ms

    ├ 测试数据 05:答案正确... 0ms

    ├ 测试数据 06:答案正确... 0ms

    ├ 测试数据 07:答案正确... 0ms

    ├ 测试数据 08:答案正确... 228ms

    ├ 测试数据 09:答案正确... 228ms

    ├ 测试数据 10:答案正确... 197ms

    ---|---|---|---|---|---|---|---|-

    Accepted 有效得分:100 有效耗时:653ms

    RP不太好

    F=F[J]+SUM-SUM[J]-I*100

    F[J]-I*100>0

    I>J>0

    用一个queue维护f中的递增队列。IMJGOOD已经给了详细的说明

    每次从开头找到能跳到i的值就可以了

    注意 sum要预处理。

  • 0
    @ 2009-08-17 09:14:11

    Orz.

  • 0
    @ 2009-08-17 08:41:27

    我用单调队列乱搞的就AC了……

  • 0
    @ 2009-08-17 10:10:05

    F [ I ] 表示的是最后一次跳跃至I能保留的最大能量值. SUM[ I ]表示从1~I的能量球总和

    那么转移是 F [ I ] = F [ J ] + SUM [ I ] - SUM [ J ]-I*100

    前提是F [ J ] >= i * 100 (不然跳不到);

    那么对于K1 < K2

    设F [ I ]由K 转移来的值为S ( K , I ),那么如果有S ( K1 , I ) SUM [ K2 ] - SUM [ K1 ]

    也就是说当 S ( K2 , I ) > S ( K1 , I ) (可以推广到任意I因为F [ K ] - SUM [ K ] 与 I 无关), 必有F [ K2 ] > F [ K1 ] 那么显然不论怎么样 K2 都比K1优,以后也是如此,所以删除K1,如果S ( K2 , I ) < S ( K1 , I ) 那么我们判断如果F[ K2 ] < F[ K1 ] 则删除K2,否则保留,保留的结果按K1

  • 0
    @ 2009-08-17 08:32:44

    先来占个位,考试时就这题来不及做

  • 0
    @ 2009-08-17 08:19:10

    编译通过...

    ├ 测试数据 01:答案正确... 0ms

    ├ 测试数据 02:答案正确... 0ms

    ├ 测试数据 03:答案正确... 0ms

    ├ 测试数据 04:答案正确... 0ms

    ├ 测试数据 05:答案正确... 0ms

    ├ 测试数据 06:答案正确... 0ms

    ├ 测试数据 07:答案正确... 0ms

    ├ 测试数据 08:答案正确... 212ms

    ├ 测试数据 09:答案正确... 181ms

    ├ 测试数据 10:答案正确... 197ms

    ---|---|---|---|---|---|---|---|-

    Accepted 有效得分:100 有效耗时:590ms

    维护一个O(n)的队列即可,

    WS的开了600W...哈哈

  • 0
    @ 2009-08-17 06:41:00

    把DP方程优化一下就变成递减的了然后就可以O(n)…

信息

ID
1617
难度
6
分类
动态规划 | 单调性DP 点击显示
标签
递交数
1855
已通过
469
通过率
25%
被复制
2
上传者