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