题意:给一个长度为n的排列,求长度为k+1的上升子序列个数。
很显然的DP,
f[j][i]
表示到了第i位,取了长度为j的序列。
f[j][i]=∑a[k]<=a[i]f[j−1][k]
,边界为
f[0][k]=1
。
用个主席树随便滚动地维护一下前缀和就好。
关于上升子序列系列的问题似乎都是可以这么乱搞的。
时间复杂度
O(Knlogn)
。
注意是长度为k+1……是上升子序列……
#include <bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i = a , _ = b ; i <= _ ; i ++)
#define per(i,a,b) for(int i = a , _ = b ; i >= _ ; i --)
#define cr(x) memset(x , 0 , sizeof x)
#define maxn 100007
#define maxs 2000007
inline int rd() {
char c = getchar();
while (!isdigit(c)) c = getchar() ; int x = c - '0';
while (isdigit(c = getchar())) x = x * 10 + c - '0';
return x;
}
typedef long long ll;
typedef int seg_int[maxs];
typedef ll seg_ll [maxs];
typedef int arr[maxn];
int n , m;
struct CMT {
arr rt;
seg_int lc , rc;
seg_ll val ;
int tot , p;
ll v;
void update(int pr , int&nr , int l , int r) {
if (!nr) nr = ++ tot ;
val[nr] = val[pr] + v;
if (l == r) return;
int m = l + r >> 1;
if (p <= m)
rc[nr] = rc[pr] , update(lc[pr] , lc[nr] , l , m);
else
lc[nr] = lc[pr] , update(rc[pr] , rc[nr] , m + 1 , r);
}
ll query(int&nr , int l , int r) {
if (!nr) return 0;
if (r <= p) return val[nr];
int m = l + r >> 1;
if (p <= m) return query(lc[nr] , l , m);
else return val[lc[nr]] + query(rc[nr] , m + 1 , r);
}
inline void M(int pr , int nr , int _p , ll _v) {
p = _p , v = _v;
update(rt[pr] , rt[nr] , 1 , n);
}
inline ll Q(int nr , int _p) {
p = _p;
return query(rt[nr] , 1 , n);
}
inline void C() {
tot = 0;
cr(rt) , cr(lc) , cr(rc) , cr(val);
}
}tr[2];
arr a;
void input() {
n = rd() , m = rd() + 1;
rep (i , 1 , n) a[i] = rd();
std::reverse(a + 1 , a + n + 1);
}
void solve() {
int cur = 0 , pre = 1;
per (i , n , 1) tr[cur].M(i + 1 , i , a[i] , 1);
rep (j , 2 , m) {
cur ^= 1 , pre ^= 1;
tr[cur].C();
per (i , n , 1)
tr[cur].M(i + 1 , i , a[i] , tr[pre].Q(i + 1 , a[i]));
}
using namespace std;
cout << tr[cur].Q(1 , n + 1) << endl;
}
int main() {
#ifndef ONLINE_JUDGE
freopen("data.txt" , "r" , stdin);
#endif
input();
solve();
return 0;
}