CDOJ 1217 The Battle of Chibi【树状数组+dp】

题目链接:

http://acm.uestc.edu.cn/#/problem/show/1217

题意:

给定长度为n的序列,求长度为m的严格上升子序列个数。

分析:

dp
状态转移方程:枚举长度和他前面的比他小的元素进行状态的转移,时间复杂度 O(n3)
采用树状数组进行优化,我们就可以 O(logn) 获得他前面比他小的元素的长度为 i 的上升序列个数。
由于a[i]很大,这里进行一下离散化。

/*
--I AM SUPER ROBBISH
--Created by jiangyuzhu
--2016/5/19
*/
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
#define pr(x) cout << #x << ": " << x << "  "
#define pl(x) cout << #x << ": " << x << endl;
#define sa(x) scanf("%d",&(x))
#define sal(x) scanf("%lld",&(x))
#define mdzz cout<<"mdzz"<<endl;
const int maxn = 1e3 + 5, maxm = 5, mod = 1e9 + 7, oo = 0x3f3f3f3f;
int bit[maxn][maxn];
int dp[maxn][maxn];
int nn;
int a[maxn], na[maxn];
int maxa;
void add(int i, int len, int x)
{
    while(i <= maxa){
        bit[i][len] = (x +  bit[i][len]) % mod;
        i += i & -i;
    }
}
int sum(int i, int len)
{
    int ans = 0;
    while(i){
        ans = (ans + bit[i][len]) % mod;
        i -= i &-i;
    }
    return ans % mod;
}
int main (void)
{
        int t;sa(t);
        int c = 1;
        while(t--){
            int n, m;sa(n);sa(m);
            for(int i = 0; i < n; i++){
                sa(a[i]);
                na[i] = a[i];
            }
            sort(na, na + n);
            nn = unique(na, na + n) - na;
            maxa = 0;
            for(int i = 0; i < n; i++){
                a[i] = lower_bound(na, na + nn,  a[i]) - na;
                a[i]++;
                maxa = max(maxa, a[i]);
            }
            memset(dp, 0, sizeof(dp));
            memset(bit, 0, sizeof(bit));

            for(int i = 0; i < n; i++){
                add(a[i], 1, 1);
                dp[i][1] = 1;
                for(int j = 2; j <= m; j++){
                    dp[i][j] = sum(a[i] - 1, j - 1);
                    add(a[i], j, dp[i][j]);
                    if(!dp[i][j]) break;
                }
            }
            printf("Case #%d: %d\n", c++, sum(maxa, m));
        }
        return 0;
}
/*
100
5 2
1 1 1 2 2
9 3
1 1 1 2 2 2 3 3 3
3 2
1 2 3
3 2
3 2 1
*/
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值