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

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

题意

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

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

[1leq n leq 3 imes 10^4 ,0leq 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

原文地址:https://www.cnblogs.com/hznumqf/p/13835924.html