「 HDOJ P2227 」 Find the nondecreasing subsequences

# 题目大意

就是找不下降子序列的个数。

 

# 解题思路

一开始想着先离散化,然后再做个 $dp$,发现用 $dp$ 的话时间复杂度是 $\text{O}(n^2)$ 的,稳稳超时。

这里说说 $dp$:

设 $dp[i]$ 表示以 $a[i]$ 为结尾的不下降子序列的个数。

那么状态转移方程就显而易见了:

$$dp[i] = sum(dp[j])+1,a[j]<=a[i]\&\&j<i$$

遂放弃 $dp$,转向另一种思路:树状数组。

因为要求逆序列的个数。所以选择用树状数组来做,思路如下:

将数据离散化后,按照原来输入的顺序从小到大将每一个数的影响加到树状数组中。那么影响是啥?

就是会对当前这个数后面的比它大的数字造成影响,因为会构成逆序列。然后你就牛逼了。。。

这样的话,每次询问一个数时,只有它前面的数的影响才被加了进去。就可以保证询问的正确性。

 

# 附上代码

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int maxn = 1e5+3, HA = 1e9+7;
int n, s[maxn], a[maxn], tmp[maxn], bit[maxn], NI[maxn];
inline int lowbit(int x) {return x & -x;}
inline void add(int pos, int num) {
    while (pos <= n) {
        bit[pos] = ((num % HA) + (bit[pos] % HA)) % HA;
        pos += lowbit(pos);
    }
}
inline int query(int pos) {
    int res = 0;
    while (pos >= 1) {
        res = ((bit[pos] % HA) + (res % HA)) % HA;
        pos -= lowbit(pos);
    }
    return res;
}
int main() {
    while (~scanf("%d", &n)) {
        memset(NI, 0, sizeof(NI));
        memset(bit, 0, sizeof(bit));
        for(int i=1; i<=n; i++) {
            scanf("%d", &s[i]);
            tmp[i] = s[i];
        }
        sort(tmp+1, tmp+1+n);
        for(int i=1; i<=n; i++)
            a[i] = lower_bound(tmp+1, tmp+1+n, s[i])-tmp;
        for(int i=1; i<=n; i++) {
            NI[i] = query(a[i]);
            NI[i] %= HA;
            add(a[i], NI[i] + 1);
        }
        printf("%d\n", query(n));
    }
}

 

posted @ 2018-09-28 15:11  Mystical-W  阅读(...)  评论(...编辑  收藏