POJ3046 多重集组合数 dp+前缀和优化+滚动数组 (包含类似优化的小总结)

原创 2015年10月27日 12:09:48

题意

  • T种数,每种有a[t]个,总共有A个数。问你取其中X个数作为子集,有多少种这样的子集。计算L<=X<=H的子集数之和,结果mod 1000000
  • 1<=T<=1000, 1<=a[t] <= 100,即1 <= A <= 100000, L<=H<=A

思路

  • 基本想法:可以类比为把求max改为求sum的多重背包,所以基本的递推关系很好写,dp(i,j) = sum dp(i-1)(j-k) 其中k = 0~a[i] ,dp(i,j)表示前i种数,其中j个数作为子集的取法。
  • 很明显,这样做会超时、超空间,超空间好说,是基本的滚动数组。我们主要解决超时的问题。
  • 前缀和优化,我们把状态改一下。dp(i,j)表示前i种数,其中0~j个数作为子集时的取法。这样dp(i,j) = dp(i-1, j) - dp(i-1, j-a[i]-1) + dp(i,j-1) 时间复杂度的问题就解决了。
  • 滚动数组,我们可以看到,每次更新i时,我们要用到i-1时的 j 和 j-a[i]-1,那么应该倒着更新j。可是这样的话,在更新dp(i,j)时,dp(i,j-1)还没有更新出来,无法更新dp(i,j)。这里我们有两种解决方案,一是,保存两个dp(j),这样我们通过用i&1找到用哪个dp,然后正向更新dp(j),另一种是,保存一个dp(j),做两次循环更新它。第一次做,dp(i,j) = dp(i-1, j) - dp(i-1, j-a[i]-1),求出不带前缀和的,第二次专门求前缀和。

一些小总结

  • 这种前缀和优化适用于每次求sum时,不用再乘一个和j相关的系数时,比如dp (i,j) = sum dp(i-1)(j-k) * c(j) 这时就无法用前缀和来优化了。
  • 滚动数组的第二种方案是我这次突然想到的,我觉得也挺好的,把问题差分了,相当于加入了一个辅助的数组,一个保存前i种数,其中j个数作为子集的取法,另一个保存前i种数,其中0~j个数作为子集时的取法,然后再更新时比较好写。
  • 另外,我想不是求sum的问题时,比如max和min也都可以用类似的想法优化。也是当没有更多相关的系数时,我们可以用RMQ问题或者线段树作为一个辅助数组,来优化时间复杂度。

实现

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;

int T,n,L,H;
const int mod = 1000000;
int dp[100005];
int a[1005];

int main(){
    int i,j;
    cin>>T>>n>>L>>H;
    for (int i=0;i<n;i++){
        int tmp;
        scanf("%d",&tmp);
        a[tmp]++;
    }
    for (int i=0;i<=H;i++)
        dp[i] = 1;
    for (int i=1;i<=T;i++){
        for (int j=H;j>=0;j--){
            if (j > a[i]){
                dp[j] = (dp[j] - dp[j-a[i]-1] + mod) % mod;
            }
        }
        for (int j=1;j<=H;j++){
            dp[j] = (dp[j] + dp[j-1]) % mod;
        }
    }
    cout << (dp[H] - dp[L-1] + mod) % mod<< '\n';

    return 0;
}
版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

动态规划算法的优化技巧

动态规划算法的优化技巧 福州第三中学   毛子青   [关键词] 动态规划、 时间复杂度、优化、状态   [摘要] 动态规划是信息学竞赛中一种常用的程序设计方法,本文着重讨论了运用动态规划...
  • Wss0130
  • Wss0130
  • 2012年09月12日 21:00
  • 2510

前缀和并行算法

多核中的并行前缀和计算 前缀和计算在并行计算中很有用,因为在处理负载平衡问题时,经常需要将若干段数据重新平分,计算前缀和通常是一种有效的将数据平分的方法。例如在并行基数排序中,就会用到了前缀和的计算...

noip数据结构与算法 之 基础小算法 1 一维前缀和维护

一维前缀和维护是一种基础的小算法,该算法用我们所熟知的数列求和方式优化我们的某些查询操作,是一种动态规划的思想。...
  • XT_NOI
  • XT_NOI
  • 2017年05月23日 20:53
  • 278

【codeforces】gym 101138 K. The World of Trains【前缀和优化dp】

题目链接:K. The World of Trains记录一个横着的前缀dp和以及斜着的前缀dp,复杂度O(n2)O(n^2)#include using namespace std ;typede...

玲珑oj 1032 (容斥原理或前缀和优化dp)

题面十分简单,n个球放m个盒子,可以空,盒子不同,要求球数最多的盒子唯一,方案数题面十分简单,n个球放m个盒子,可以空,盒子不同,要求球数最多的盒子唯一,方案数 n,m都是500,考虑复杂度O(n3...

poj3666(dp前缀优化)

链接:点击打开链接 题意:将A1....An变为B1.....Bn,要求序列B满足非严格单调递增或非严格单调递减,代价为|A1-B1|+|A2-B2|+...+|AN -BN|,输出最小代价 代码: ...

noip2016 Day2 T2-组合数问题-组合数学-前缀和

luogu P2822 右转进入题目 vijos P4761 右转进入题目 C(n,m)=C(n-1,m-1)+C(n-1,m).可以手动验证。然后,把它想象成一个矩形,如果C(n,m)=0(mo...
  • Mys_C_K
  • Mys_C_K
  • 2017年01月18日 20:14
  • 317

写给程序员的!(不要浮躁)------以此来激励自己

1.不要看到别人的回复第一句话就说:给个代码吧!你应该想想为什么。当你自己想出来再参考别人的提示,你就知道自己和别人思路的差异。 2.初学者请不要看太多太多的书那会误人子弟的,先找本系统的学,很多人...

前缀和问题

一维前缀和这个优化主要是用来在O(1)时间内求出一个序列a中,a[i]+a[i+1]+……+a[j]的和。具体原理十分简单:用sum[i]表示(a[1]+a[2]+……+a[i]),其中sum[0]=...
  • K_rew
  • K_rew
  • 2016年01月16日 11:18
  • 3238

DP 优化系列

我知道,我现在写这篇文章还很不成熟,因为我很多东西弄得还很不怎么样,但是我还是想写一下。 国家集训队论文中有大量关于DP优化的论文:毛子青的《动态规划算法的优化技巧》、朱晨光的《从《鹰蛋》一题浅析对...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:POJ3046 多重集组合数 dp+前缀和优化+滚动数组 (包含类似优化的小总结)
举报原因:
原因补充:

(最多只允许输入30个字)