递增子序列
金牌导航 数据结构优化DP-1
题目大意
给出一个序列,让你求长度为m的单调递增子序列的个数
输入样例
3 2
1 1 2
7 3
1 7 3 5 9 4 8
输出样例
2
12
数据范围
1⩽n⩽104,1⩽m⩽100,0⩽ai⩽9876543211\leqslant n \leqslant 10^4,1\leqslant m \leqslant 100,0\leqslant a_i \leqslant 9876543211⩽n⩽104,1⩽m⩽100,0⩽ai⩽987654321
解题思路
对于第i个数,如果要使以它结尾的单调递增子序列长度为j,那么就要在前面找到比aia_iai小的数,累加以它们为结尾长度为j-1的单调递增序列(就是把i接到后面)
如果直接DP枚举,会TLE
这时可以用树状数组在O(logn)O(logn)O(logn)的时间内求出累加的值,没计算出一个数,就加进树状数组中
代码
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
#define N 100010
#define wyc 123456789//orz
using namespace std;
int n, m, l, x, a[N], b[N], c[101][N];
void add(int g, int x, int y)
{for (; x <= l; x += x&-x)c[g][x] = (c[g][x] + y) % wyc;
}
int ask(int g, int x)
{int y = 0;for (; x; x -= x&-x)y = (y + c[g][x]) % wyc;return y;
}
int main()
{while(~scanf("%d%d", &n, &m)){memset(c, 0, sizeof(c));for (int i = 1; i <= n; ++i){scanf("%d", &a[i]);b[i] = a[i];}sort(a + 1, a + 1 + n);l = unique(a + 1, a + 1 + n) - a - 1;//离散化for (int i = 1; i <= n; ++i){x = lower_bound(a + 1, a + 1 + l, b[i]) - a;for (int j = m; j > 1; --j)add(j, x, ask(j - 1, x - 1));//求累加值,再加到树状数组中add(1, x, 1);}printf("%d\n", ask(m, l));}return 0;
}