Loading

P1637 三元上升子序列 树状数组优化DP

P1637 三元上升子序列 树状数组优化DP

题意

由于元比较小,实际上可以推广到\(M\)元上升子序列,用树状数组优化转移方程,复杂度\(O(MNlogN)\)

给定的数组\(a\)中问有多少个三元上升子序列。

\[1\leq n \leq 3 \times 10^4 ,0\leq a_i \leq 2^{63} \]

分析

仿照\(LIS\),设\(dp[i][j]\)表示长度为\(i\)的以\(a[j]\)结尾的上升子序列的个数。

转移方程

\[f[i][j] = \sum_{k<j,a[k]<a[j]}f[i-1][k] \]

我们用“权值树状数组"优化转移即可

由于\(a[i]\)比较大,还需要离散化一下

代码

ll a[maxn], s[maxn];
ll f[4][maxn];
int n;

struct BIT {
    int n;
    ll c[maxn];
    ll ask(int x) {
        ll sum = 0;
        for (; x; x -= x & (-x))
            sum += c[x];
        return sum;
    }
    void add(int x, ll v) {
        for (; x <= n; x += x & (-x))
            c[x] += v;
    }
};

int main() {
    n = readint();
    for (int i = 1; i <= n; i++)
        a[i] = readint(), s[i] = a[i];
    sort(s + 1, s + n + 1);
    int m = unique(s + 1, s + n + 1) - (s + 1);
    BIT b;
    b.n = m;
    for (int i = 1; i <= n; i++)
        f[1][i] = 1, a[i] = lower_bound(s + 1, s + m + 1, a[i]) - s;
    for (int i = 2; i <= 3; i++) {
        memset(b.c, 0, sizeof b.c);
        for (int j = 1; j <= n; j++) {
            f[i][j] = b.ask(a[j] - 1);
            b.add(a[j], f[i - 1][j]);
        }
    }
    ll res = 0;
    for (int i = 1; i <= n; i++)
        res += f[3][i];
    Put(res);
}

参考

[]: https://www.luogu.com.cn/blog/huangchangmiao/solution-p1637

posted @ 2020-10-18 16:43  MQFLLY  阅读(104)  评论(0编辑  收藏  举报