题解:P13037 [GCJ 2021 #2] Hidden Pancakes
tag: 组合数学,单调栈,笛卡尔树,DP。
首先无解情况是
考虑对已知信息进行一些大小判断。覆盖操作类似单调栈,所以考虑建出笛卡尔树。
我们知道了树根
这个方法也可以推广到任意子树。时间复杂度
#include <bits/stdc++.h>
#define ll long long
#define pii pair <int, int>
#define pll pair <ll, ll>
#define fi first
#define se second
#define y1 noip200
#define stp(x) fixed << setprecision(x)
using namespace std;
const int N = 1e5 + 50, p = 1e9 + 7, inf = 1 << 29;
int n, stk[N], top, f[N], sz[N], fa[N];
int mul1[N], mul2[N];
vector <int> e[N];
void init() {
mul1[0] = 1;
for (int i = 1; i <= 100000; i++) mul1[i] = 1LL * mul1[i - 1] * i % p;
mul2[0] = mul2[1] = 1;
for (int i = 2; i <= 100000; i++) mul2[i] = 1LL * (p - p / i) * mul2[p % i] % p;
for (int i = 1; i <= 100000; i++) mul2[i] = 1LL * mul2[i - 1] * mul2[i] % p;
}
int C(int x, int y) {
return 1LL * mul1[x] * mul2[y] % p * mul2[x - y] % p;
}
void dfs(int u) {
for (auto v : e[u]) {
if (v == fa[u]) continue;
dfs(v);
sz[u] += sz[v];
f[u] = 1LL * f[u] * f[v] % p * C(sz[u], sz[v]) % p;
}
sz[u]++;
}
void solve() {
cin >> n;
top = 0;
int rt = 0, ok = 1;
for (int i = 1; i <= n; i++) f[i] = 1, e[i].clear(), sz[i] = 0, fa[i] = 0, stk[i] = 0;
for (int i = 1; i <= n; i++) {
int x;
cin >> x;
if (x >= top + 2)
ok = 0;
while (top > x) stk[top--] = 0;
if (top >= x) --top;
fa[stk[top + 1]] = i;
fa[i] = stk[top];
if (!top) rt = i;
stk[++top] = i;
}
if (!ok) {
cout << 0 << endl;
return;
}
for (int i = 1; i <= n; i++) e[fa[i]].push_back(i);
dfs(rt);
cout << f[rt] << endl;
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
init();
int t = 1;
cin >> t;
for (int i = 1; i <= t; i++)
cout << "Case #" << i << ": ", solve();
return 0;
}