1
+ /*
2
+ COCI 2008 Periodni
3
+ - Notice how if we move from the y row upward, we get "islands" forming
4
+ - Each island is independent and is also a smaller periodic table
5
+ - This suggests that since the periodic table has no "donuts", we should
6
+ compress it into a rooted tree
7
+ - Kinda like IOI 2012 Ideal City
8
+ - The root node of a periodic table is the largest rectangle we can make from
9
+ the y few rows
10
+ - We can then recursively generate the rest of the tree
11
+ - dp[i][j] = The number of ways to put j noble gases in node i's subtree
12
+ - tmp[i][j] = dp[i][j] but we put no noble gases in node i
13
+ - dp[i][j] = sum(tmp[i][k] * choose(width[i] - k, j) * choose(height[i], j) * j!)
14
+ - Complexity: O(N^2 * K)
15
+ */
16
+
17
+ #include < bits/stdc++.h>
18
+ #define FOR (i, x, y ) for (int i = x; i < y; i++)
19
+ typedef long long ll;
20
+ using namespace std ;
21
+
22
+ const ll MOD = 1e9 + 7 ;
23
+
24
+ int n, m = 0 , k, h[500 ];
25
+ ll fact[1000001 ]{1 }, inv_fact[1000001 ]{1 };
26
+ ll width[500 ], height[500 ], dp[500 ][501 ], tmp[501 ];
27
+ vector<int > graph[500 ];
28
+
29
+ ll expo (ll base, ll pow) {
30
+ ll ans = 1 ;
31
+ while (pow ) {
32
+ if (pow & 1 ) ans = ans * base % MOD;
33
+ pow >>= 1 ;
34
+ base = base * base % MOD;
35
+ }
36
+ return ans;
37
+ }
38
+
39
+ ll choose (ll x, ll y) {
40
+ if (x < y) return 0 ;
41
+ return fact[x] * inv_fact[y] % MOD * inv_fact[x - y] % MOD;
42
+ }
43
+
44
+ void construct_tree (int l = 0 , int r = n - 1 , int dh = 0 ) {
45
+ int min_h = *min_element (h + l, h + r + 1 );
46
+ width[m] = r - l + 1 ;
47
+ height[m] = min_h - dh;
48
+
49
+ int curr_idx = m++, curr_l = l;
50
+ FOR (i, l, r + 1 ) {
51
+ if (h[i] == min_h) {
52
+ if (curr_l != i) {
53
+ graph[curr_idx].push_back (m);
54
+ construct_tree (curr_l, i - 1 , min_h);
55
+ }
56
+ curr_l = i + 1 ;
57
+ }
58
+ }
59
+ if (curr_l != r + 1 ) {
60
+ graph[curr_idx].push_back (m);
61
+ construct_tree (curr_l, r, min_h);
62
+ }
63
+ }
64
+
65
+ void dfs (int node = 0 ) {
66
+ dp[node][0 ] = 1 ;
67
+ for (int i : graph[node]) {
68
+ dfs (i);
69
+ memset (tmp, 0 , sizeof tmp);
70
+ FOR (j, 0 , width[node] + 1 ) {
71
+ FOR (k, 0 , width[i] + 1 ) {
72
+ if (j + k > width[node]) continue ;
73
+ (tmp[j + k] += dp[node][j] * dp[i][k]) %= MOD;
74
+ }
75
+ }
76
+ FOR (j, 0 , width[node] + 1 ) dp[node][j] = tmp[j];
77
+ }
78
+
79
+ memset (tmp, 0 , sizeof tmp);
80
+ FOR (i, 0 , width[node] + 1 ) {
81
+ FOR (j, 0 , width[node] + 1 ) {
82
+ if (i + j > width[node]) continue ;
83
+ ll x = dp[node][i];
84
+ ll y = choose (width[node] - i, j) * choose (height[node], j) % MOD * fact[j] % MOD;
85
+ (tmp[i + j] += x * y) %= MOD;
86
+ }
87
+ }
88
+ FOR (i, 0 , width[node] + 1 ) dp[node][i] = tmp[i];
89
+ }
90
+
91
+ int main () {
92
+ ios_base::sync_with_stdio (0 );
93
+ cin.tie (0 );
94
+ FOR (i, 1 , 1000001 ) {
95
+ fact[i] = fact[i - 1 ] * i % MOD;
96
+ inv_fact[i] = expo (fact[i], MOD - 2 );
97
+ }
98
+
99
+ cin >> n >> k;
100
+ FOR (i, 0 , n) cin >> h[i];
101
+ construct_tree ();
102
+ dfs ();
103
+ cout << dp[0 ][k];
104
+ return 0 ;
105
+ }
0 commit comments