• 基础dp例题整理


    背包:

    消失之物

    先直接做一遍,必然对于i,有

    for(j=m;j>=w[i];--j)

    f[i]+=f[i-w[i]]

    所以,如果排除用i做背包的结果,减去这个转移就好了。

    memcpy(g,f,sizeof f)

    for(j=w[i];j<=m;++j)

    g[j]-=g[j-w[i]]

    关于i的一行就都有了。

    [POI2012]SZA-Cloakroom

    又是一个有三个属性的题。

    肯定要离线。询问关于m排序,物品按照a排序。

    k比较小,n比较小。

    f[i]表示,决策到当前这个a为止,凑成和为i的所有方案中,最小的b最大是多少。(为了保证bi>m+s)

    这样,每到一个决策点m,就可以利用当前处理的f[k]>m+s即可判断能否实现。

    因为保证的是最小的b最大是多少。正确性显然。

     

    怎么处理的三个属性呢?a当做顺序,c当做状态,b当做数值。再加上离线对m排序。然后求最小的b最大是多少,直接把配凑问题转化成判定问题。

    复杂度O(1e8)可过。

    [HNOI2007]梦幻岛宝珠

    bzoj1190 [HNOI2007]梦幻岛宝珠 ( 二进制分组优化背包DP)

    分层DP。以b为层。

    f[i][j]表示,小于等于j*2^i+(w&(1<<(i-1))的最大价值。

    每层就是一个0/1背包。

    然后考虑逐层合并出来真正的f[i][j]

    从低位往高位合并。

    f[i][j]=max(f[i][j],f[i][j-k]+f[i-1][min(1000,2*k+((w>>(i-1))&1)]

    意义是:把j拆出来k位,用i-1两倍的k来凑出来,然后为了保证+(w&(1<<(i-1))这个东西,就要保证i-1必要时提供一个1*2^(i-1)

    至于对1000取min,是可以的。因为本身就不可能达到,而本身就是一个前缀min,这样找不可能超出。

    至于那一步加法也是可以的,f[i][j-k]还只是当前层的,就相当于把当前层取出来一些,再把低位的一些取出来拼凑。

    至于f[i][j]弄出来前缀的特点,就不要把f[i][j]初值-inf即可。

    具体代码见上面的博客(虽然有错)

    树形dp

    [SCOI2015]小凸玩密室

    厉害的树形dp。

    神奇的状态设计。

    一些需要考虑的细节。

    由于起点不定,所以,填法有两种:

    1.填完这个子树后,点某个祖先。

    2.填完这个子树后,点某个祖先的兄弟。

    dp[i][j][0/1]表示,填完以i为根的子树,再取点第j个祖先/第j个祖先的兄弟的代价。

    每个点只能在被点到的时候统计贡献,因为这样才能知道距离。nlogn

    其实就是一个对未来的承诺。

    因为我们不知道填完这个上一个是哪一个,就不能统计贡献。

    所以,干脆,就在填完这个之后,直接枚举下一个是哪一个,然后就把贡献算上即可。真在那里填的话,贡献就已经算好了。

    而且,祖先只有logn个,下一个填哪一个的方案数比较少。

     

    然后要处理答案。

    发现,当起点固定的话,必然要先点完整个子树,然后点父亲,点兄弟子树,再点爷爷,点叔叔子树。

    所以,一路模拟即可。

    处理答案的复杂度:nlogn

    https://blog.chenqiqian.com/20180608-SCOI2015-room/

  • 相关阅读:
    等待事件统计信息--Wait Events Statistics
    实时监控SQL
    PHP中常用的魔术方法
    PHP生成缩略图(3)--封装类
    PHP生成缩略图(2)--等比缩略图
    PHP生成缩略图(1)--简单缩略图
    调用天气预报接口
    使用JSON实现分页
    使用AJAX实现分页
    AJAX缓存问题
  • 原文地址:https://www.cnblogs.com/Miracevin/p/9839129.html
Copyright © 2020-2023  润新知