TIOJ-2066

$T$筆測資,

每筆測資給一$N$項數列及一數字$K$,求長度介於$[1,K]$的相異遞增子序列數量$\mod 2^{61}-1$。

$T\le 8,N\le 10^5,K\le 70, 1\le a_i\le 10^9$


令$dp[i][j]$為結尾為$a_i$,且長度為$j$的遞增子序列數量,轉移式為:
$$dp[i][j] = \sum^{i}_{k=1} dp[k][j-1],\ a_k<a_i$$
以上轉移可用單點修改,求前綴和的資料結構來達到$\mathcal{O}(log n)$轉移。

將$a_i$當成index,$dp[i][j-1]$當成value,上述dp的轉移可視為求$1$到$a_i-1$的前綴和,但$a_i$範圍太大,需要先離散化。

且最後一筆會卡空間,因此必須將$j$那一維壓成滾動。

時間複雜度$\mathcal{O}(TNK)$,空間複雜度$\mathcal{O}(N)$

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
/*
-------------- | /
| | /
| | /
| * |/ | | ------ *
| | | | / \
| | |\ | | | |\ |
\ | | | \ | | | | \ |
\ | | | \ | | \ / \ |
V | | \ \__/| ----- \ |
*/
#include <bits/stdc++.h>
using namespace std;

#define EmiliaMyWife ios::sync_with_stdio(0); cin.tie(NULL);
using ll = int64_t;
/*-----------------------------------------------------------------------------------------------------*/

const ll mod = (1LL<<61)-1;

const int N = 1e5+25;
ll bit[N];
void modify(int p, ll val) {
for(; p<N; p+=p&-p)
bit[p] = (bit[p] + val) % mod;
}
ll sum(int p) {
ll res = 0;
for(; p; p-=p&-p)
res = (res + bit[p]) % mod;
return res;
}

signed main() {
EmiliaMyWife

int t;
cin >> t;
while(t--) {
int n, k;
cin >> n >> k;
vector<int> arr(n+1), v;
vector<vector<ll>> dp(2, vector<ll>(n+1));
for(int i = 1; i <= n; i++)
cin >> arr[i], v.push_back(arr[i]);
v.push_back(0);
sort(v.begin(), v.end()); v.erase(unique(v.begin(), v.end()), v.end());
for(int i = 0; i <= n; i++)
arr[i] = upper_bound(v.begin(), v.end(), arr[i])-v.begin();
dp[0][0] = 1;
ll ans = 0;
int now = 1, prv = 0;
for(int i = 1; i <= k; i++) {
memset(bit, 0, sizeof bit);
for(int j = 0; j <= n; j++)
dp[now][j] = 0;
for(int j = 1; j <= n; j++) {
modify(arr[j-1], dp[prv][j-1]);
dp[now][j] = sum(arr[j]-1);
ans = (ans + dp[now][j]) % mod;
}
swap(now, prv);
}
cout << ans << '\n';
}

return 0;
}