zoukankan      html  css  js  c++  java
  • HDU 2836 (离散化DP+区间优化)

    Reference:http://www.cnblogs.com/wuyiqi/archive/2012/03/28/2420916.html

    题目链接http://acm.hdu.edu.cn/showproblem.php?pid=2836

    题目大意:计算序列有多少种组合,每个组合至少两个数,使得组合中相邻两个数之差不超过H,序列有重复的数。MOD 9901。

    解题思路

    朴素O(n^2)

    以样例1 3 7 5为例,如果没有重复的数。

    设dp[i]前n个数的方案数,初始化为1。

    那么for(1...i...N)

       $dp[i]=sum dp[j]+1quad,where quad left |num[i]-num[j] ight|<=H$

    +1是为了计算两个点直接连接的情况,如样例:

    dp[1]=1 (无连接)

    dp[2]=dp[1]+1=2 (1-3连接)

    dp[3]=1 (无连接)

    dp[4]=dp[2]+dp[3]+1=4(1-3-5, 3-5,7-5)

    如果没有+1,那么就没法dp下去,同时,这样每个点多算了1,所以ans=1+2+1+4-4=4

    快速求和优化

    上面O(n^2)的原因在于, 原始序列的dp区间不是连续的,比如1,3,8,3,5,7 H=2

    5的dp区间可以是2,4,需要多扫一轮来找出这些离散的值。

    实际上,dp过程中可以不依赖原始序列顺序。将原始序列排序离散化去重后,变成1,3,5,8

    这样,新添加一个box的时候,可以二分找其值在新序列中边界L,R,这样,原本的离散dp求和,

    被转化成了连续区间求和$sum sum(R)-sum(L-1)$

    原因很简单,5在实际计算时,在3,3,7中都被牵扯到,是一个对称计算。所以排序去重后可以简化为对连续区间的计算。

    至于为什么要去重,主要是为了解决重值的重复计算(原题并没有说没有重值)

    比如1,3,3,如果不去重,为第二个3单独开个dp状态,那么1-3被算了两次(dp初始值为1)

    所以第二个3,无须再开一个dp状态,直接第一个3基础上算就行了。保证ans-n是最后的结果。

    代码

    #include "cstdio"
    #include "algorithm"
    #include "cstring"
    using namespace std;
    #define maxn 100005
    #define mod 9901
    int num[maxn],Hash[maxn],n,h,s[maxn];
    int lowbit(int x) {return x&(-x);}
    int sum(int x)
    {
        int ret=0;
        while(x>0) ret=(ret+s[x])%mod,x-=lowbit(x);
        return ret%mod;
    }
    void update(int x,int d)
    {
        while(x<=n) s[x]=(s[x]+d)%mod,x+=lowbit(x);
    }
    int main()
    {
        //freopen("in.txt","r",stdin);
        while(scanf("%d%d",&n,&h)!=EOF)
        {
            memset(Hash,0,sizeof(Hash));
            memset(s,0,sizeof(s));
            for(int i=1;i<=n;i++)
            {
                scanf("%d",&num[i]);
                Hash[i]=num[i];
            }
            sort(Hash+1,Hash+n+1);
            int diff=unique(Hash+1,Hash+n+1)-Hash-1;
            int ans=0;
            for(int i=1;i<=n;i++)
            {
                int idx=lower_bound(Hash+1,Hash+diff+1,num[i])-Hash;
                int L=lower_bound(Hash+1,Hash+diff+1,num[i]-h)-Hash;
                int R=upper_bound(Hash+1,Hash+diff+1,num[i]+h)-Hash-1;
                int dp=(sum(R)-sum(L-1)+1)%mod;
                ans+=dp;
                update(idx,dp);
            }
            printf("%d
    ",(ans-n)%mod);
        }
    }
  • 相关阅读:
    前端安全【面试】
    防xss攻击
    前端工程化
    前端项目构建——运维
    react入门
    OpenGL Windows 窗口程序环境搭建
    Django 列的自定义显示
    设计模式之 SOA面向服务的体系
    设计模式之Builder建造者模式 代码初见
    设计模式之Factory工厂模式的好处
  • 原文地址:https://www.cnblogs.com/neopenx/p/4528843.html
Copyright © 2011-2022 走看看