Fork me on GitHub

HDU 4990 Ordered Subsequence --数据结构优化DP

题意:给一串数字,问长度为m的严格上升子序列有多少个

解法:首先可以离散化为10000以内,再进行dp,令dp[i][j]为以第i个元素结尾的长度为j的上升子序列的个数,

则有dp[i][j] = SUM(dp[k][j-1])  (a[k] < a[i] && k < i)

不可能直接遍历,所以考虑优化,可以看出dp方程相当于一个区间求和,所以可以用树状数组来优化。

代码:

#include <iostream>
#include <cmath>
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#define SMod 123456789
#define lll __int64
using namespace std;
#define N 10007

lll c[N],a[N],b[N];
int n,m;
lll dp[N][104];

int lowbit(int x)
{
    return x & (-x);
}

void modify(int pos,lll val)
{
    while(pos <= n)
    {
        c[pos] += val;
        pos += lowbit(pos);
    }
}

lll getsum(int pos)
{
    lll res = 0;
    while(pos > 0)
    {
        res = (res+c[pos])%SMod;
        pos -= lowbit(pos);
    }
    return res;
}

int main()
{
    int i,j;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        for(i=1;i<=n;i++)
        {
            scanf("%I64d",&a[i]);
            b[i] = a[i];
        }
        sort(b+1,b+n+1);
        memset(dp,0,sizeof(dp));
        for(i=1;i<=n;i++)
            dp[i][1] = 1;
        for(j=2;j<=m;j++)
        {
            memset(c,0,sizeof(c));
            for(i=1;i<=n;i++)
            {
                int ind = lower_bound(b+1,b+n+1,a[i])-b;
                dp[i][j] = getsum(ind-1);
                modify(ind,dp[i][j-1]);
            }
        }
        lll ans = 0;
        for(i=1;i<=n;i++)
            ans = (ans + dp[i][m])%SMod;
        printf("%I64d\n",ans);
    }
    return 0;
}
View Code

 

posted @ 2014-09-08 00:58  whatbeg  阅读(315)  评论(0编辑  收藏  举报