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