HDU - 2227 Find the nondecreasing subsequences (树状数组 + 子序列 + 离散化)

HDU - 2227
Time Limit: 5000MS Memory Limit: 32768KB 64bit IO Format: %I64d & %I64u

 Status

Description

How many nondecreasing subsequences can you find in the sequence S = {s1, s2, s3, ...., sn} ? For example, we assume that S = {1, 2, 3}, and you can find seven nondecreasing subsequences, {1}, {2}, {3}, {1, 2}, {1, 3}, {2, 3}, {1, 2, 3}.
 

Input

The input consists of multiple test cases. Each case begins with a line containing a positive integer n that is the length of the sequence S, the next line contains n integers {s1, s2, s3, ...., sn}, 1 <= n <= 100000, 0 <= si <= 2^31.
 

Output

For each test case, output one line containing the number of nondecreasing subsequences you can find from the sequence S, the answer should % 1000000007.
 

Sample Input

        
        
3 1 2 3
 

Sample Output

        
        
7
题意:给予一个序列求解所构成的不下降子序列的个数 
通过离散化,将0->2^32分散到0->1e5之中
到达j处的不下降子序列的个数dp[j] = sum{dp[i]} + 1 {i < j && S[i] <= S[j] && i > 0};
状态方程推导:
假设dp[j]为S[j]为结尾的序列的个数
那么if(S[j] < S[i])那么 dp[i] += dp[j]
为什么呢,举个简单的例子
如果以S[j]为结尾的序列是一下:
最原始的序列:S = { 1, 5, 3, 6, 7, 5, 2, 1, 8, 9};
如果j = 4的话
那么以S[j]为结尾的不下降子序列如下:
6
1 6
5 6
3 6
1 3 6
1 5 6
那么如果我们取i = 5时
S[i] >= S[j]可以得到
6 7
1 6 7
5 6 7
3 6 7
1 3 6 7
1 5 6 7
就是dp[i] += dp[j]如此将所有S[j] <= S[i]都加起来
然后加上本身7加上那么状态转移方程极为dp[i] = sum{dp[j]} + 1

如此计算sum{dp[j],i < j && S[i] <= S[j] && i > 0}便是我们的难题了
而求和问题解决的话,可以基本能分为三类:
一:树状数组
二:线段树
三:前缀和
此处则是用了树状数组求解满足条件的数据和

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;
typedef long long LL;
const int MAXN = 1e5 + 5;
const LL mod = 1e9 + 7;
int N, A[MAXN], S[MAXN];
LL C[MAXN];

int Crete(LL x) {
    int lb = 0,ub = N;
    while(ub - lb > 1) {
        int mid = (lb + ub) >> 1;
        if(A[mid] >= x) ub = mid;
        else lb = mid;
    }
    return ub;
}

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

void add(int x,LL c) {
    while(x <= N) {
        C[x] += c;
        C[x] %= mod;
        x += lowbit(x);
    }
}

int sum(int x) {
    LL ret = 0;
    while(x > 0) {
        ret += C[x];
        ret %= mod;
        x -= lowbit(x);
    }
    return ret;
}



int main() {
    while(~ scanf("%d", &N)) {
        for(int i = 1; i <= N; i ++) {
            scanf("%d", &S[i]);
            A[i] = S[i];
        }
        sort(A + 1, A + N + 1);
        LL ans = 0;
        memset(C, 0, sizeof(C));
        for(int i = 1; i <= N; i ++) {
            int ret = lower_bound(A + 1, A + N + 1, S[i]) - A;
            //int ret = Crete(S[i]);
            int res = sum(ret) + 1;
            ans += res;
            ans %= mod;
            add(ret, res);
        }
        printf("%I64d\n", ans % mod);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值