@(K ACMer)
题意:
由1到n,共n个数构成的序列中长为k + 1的上升子序列有多少个?
分析:
注意到题中数字是1到n,且子序列最长只有11.我们可以这样定义状态:
dp[i][j]
为长度为i的子序列中,末尾数以j结尾的个数.
那么容易有转移方程:
dp[i][j]=∑t=1...j−1dp[i−1][t]
显然这个复杂度是
O(k∗n2)
的,过大,注意到我们这里每次都是求的数组的前缀和,那不是用一个树状数组来维护就好了么?这样复杂度就变为了
O(k∗n∗logn)
code:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <set>
#include <map>
#include <stack>
#include <vector>
#include <string>
#include <queue>
#include <cstdlib>
#include <cmath>
#include <algorithm>
using namespace std;
typedef pair<int, int> pii;
typedef unsigned long long ll;
typedef vector<int> vi;
#define xx first
#define yy second
const int mod = int(1e9) + 7, INF = 0x3fffffff, maxn = 1e5 + 41;
ll dp[12][maxn];
int n, k, ans;
ll sum(int x, int i) {
ll ret = 0;
while (i > 0) {
ret += dp[x][i];
i -= i & -i;
}
return ret;
}
void add(int y, int i, ll x) {
while (i <= n) {
dp[y][i] += x;
i += i & -i;
}
return;
}
int main(void) {
scanf("%d%d", &n, &k);
for (int i = 0; i < n; i++) {
int x;
scanf("%d", &x);
for (int i = k + 1; i >= 1; i--) {
ll temp = (i - 1 == 0) ? 1 :sum(i - 1, x - 1);
add(i, x, temp);
}
}
cout << sum(k + 1, n) << endl;
return 0;
}