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