码迷,mamicode.com
首页 > 编程语言 > 详细

ccpc_南阳 C The Battle of chibi dp + 树状数组

时间:2015-10-21 22:19:49      阅读:267      评论:0      收藏:0      [点我收藏+]

标签:

题意:给你一个n个数的序列,要求从中找出含m个数的严格递增子序列,求能找出多少种不同的方案

dp[i][j]表示以第i个数结尾,形成的严格递增子序列长度为j的方案数

那么最终的答案应该就是sigma(dp[i][m]);

显然有:dp[i][j] = sigma(dp[k][j - 1]); 其中 1 <= k < i 且 a[k] < a[i];

题目要求严格递增,这个限制怎么解决?

hdu4719这道题同样是这样处理,即我们只需要从小到大dp就行了。

但是复杂度是O(n^3)的,显然需要优化,注意到应该从小到大dp之后,我们要做的就是快速求出sigma(dp[k][j-1])  (还未计算到的dp值为0) (注意不能直接用数组维护前缀和)

可以用树状数组得到优化,最终复杂度是O(n^2logn)

#include <bits/stdc++.h>
#define lowbit(x) (x) & (-x)
using namespace std;

const int N = 1005;
const int M = 1e9 + 7;

int dp[N][N], c[N][N];
int a[N], r[N];

bool cmp(int b, int c) {
    return a[b] < a[c];
}

void update(int i, int j, int value)
{
    while(i < N) {
        c[i][j] = c[i][j] + value % M;
        i += lowbit(i);
    }
}
int sum(int i, int j)
{
    int s = 0;
    while(i > 0) {
        s = s + c[i][j] % M;
        i -= lowbit(i);
    }
    return s % M;
}
int main()
{
    int n, m;
    int _, cas = 1; scanf("%d", &_);
    while(_ --)
    {
        scanf("%d%d", &n, &m);
        for(int i = 1; i <= n; ++i) scanf("%d", &a[i]);
        memset(c, 0, sizeof c);
        memset(dp, 0, sizeof dp);
        for(int i = 0; i <= n; ++i) r[i] = i;
        sort(r + 1, r + n + 1, cmp);

        for(int i = 1; i <= n; ++i) {
            int id = r[i];
            dp[id][1] = 1;
            update(id, 1, 1);
            for(int j = 2; j <= m; ++j) {
                dp[id][j] = sum(id - 1, j - 1);
                update(id, j, dp[id][j]);
            }
        }
        
        int ans = 0;
        for(int i = 1; i <= n; ++i) ans = ans + dp[i][m] % M;
        printf("Case #%d: %d\n", cas++, ans % M);
    }
    return 0;
}

  

 

ccpc_南阳 C The Battle of chibi dp + 树状数组

标签:

原文地址:http://www.cnblogs.com/orchidzjl/p/4899095.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!