CF1874F Jellyfish and OEIS
第一次独立切 *3500,写篇题解记录一下
我们称 \([l,r]\) 为一个排列,当且仅当 \([p_l,p_{l+1},\dots,p_r]\) 为 \([l,l+1,\dots,r]\) 的一个排列。
不妨固定 \(l\),我们只需要考虑最小的 \(r\) 满足 \([l,r]\) 为一个排列。考虑每个 \([l,r]\) 所构成的区间,如果 \([l_1,r_1],[l_2,r_2]\) 相交且不包含,不妨设 \(l_1<l_2\le r_1<r_2\),那么 \([l_2,r_1]\) 必然为一个排列,与定义矛盾,所以所有 \([l,r]\) 区间构成一个树形结构。
设 \(f_{i,j}\) 表示 \(i\) 的对应最小的 \(j\) 满足 \([i,j]\) 为一个排列,且满足 \([i,j]\) 中的所有的限制的方案数。一个暴力的转移是枚举其中若干不交区间的 \(f\) 的乘积,为 \([i,j]\) 在树上的下一层,设其长度和为 \(L\),那么还需要乘上 \(h_{j-i+1-L}\) 进行加和,其中 \(h_n\) 表示长度为 \(n\) 的排列满足除了 \([1,n]\) 的所有子区间不为排列。
设 \(g_{i,j,k}\) 表示 \([i+1,j]\) 中选取若干区间的 \(f\) 的乘积,满足区间长度和为 \(k\),这个可以在按照长度递增 dp \(f\) 时顺便更新,目前 dp 到的长度为 \(len\),那么就可以更新所有 \(g_{i,i+len-1,k}\) 。
\(h\) 考虑容斥,钦定 \(i\) 个不相交的区间,表示这 \(i\) 个区间为对应的 \(l\) 的最小的 \(r\),那么每个区间内部的方案为 \(h_{len}\),每次需要再设 \(a_{i,j}\) 表示前 \(i\) 个数中钦定区间总长度为 \(j\),转移时带上 \((-1)\) 的容斥系数。对于没有钦定的 \(n-j\) 个数可以随便填,方案数为 \((n-j)!\) 。
最后需要把若干 \(f\) 进行合并,设 \(b_i\) 表示目前合并到 \(i\),枚举 \(j\),转移为 \(b_i=\sum\limits_{j=1}^{i}b_{i-j}f_{i-j+1,i}\) 。
至此,\(g\) 的转移是 \(\mathcal{O}(n^4)\) 的,\(f,h\) 的转移是 \(\mathcal{O}(n^3)\) 的,那么总复杂度就是 \(\mathcal{O}(n^4)\) 的。
实现时显然常数很小,所以 \(n=200\) 可以过。
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 205, mod = 1e9 + 7;
void add(int & x, int y) {x += y; if (x >= mod) x -= mod;}
void dec(int & x, int y) {x += mod - y; if (x >= mod) x -= mod;}
int pls(int x, int y) {x += y; if (x >= mod) x -= mod; return x;}
int sub(int x, int y) {x += mod - y; if (x >= mod) x -= mod; return x;}
int mul(int x, int y) {return 1ll * x * y % mod;}
int n, m[N], f[N][N], g[N][N][N], h[N], fac[N], a[N][N], b[N];
bool END;
signed main() {
cin >> n; for (int i = 1; i <= n; ++i) cin >> m[i];
fac[0] = 1; for (int i = 1; i <= n; ++i) fac[i] = mul(fac[i - 1], i);
h[1] = 1;
for (int i = 2; i <= n; ++i) {
memset(a, 0, sizeof a), a[0][0] = 1;
for (int j = 1; j <= i; ++j) {
for (int k = 0; k <= j; ++k) {
a[j][k] = a[j - 1][k];
for (int l = 1; l <= min(i - 1, k); ++l)
dec(a[j][k], mul(a[j - l][k - l], h[l]));
}
}
for (int j = 0; j <= i; ++j) add(h[i], mul(a[i][j], fac[i - j]));
}
for (int i = 1; i <= n; ++i) f[i][i] = (m[i] < i), f[i + 1][i] = g[i][i - 1][0] = 1;
h[1] = 0;
for (int len = 2; len <= n; ++len)
for (int i = 1; i + len - 1 <= n; ++i) {
int j = i + len - 1;
for (int k = 0; k <= j - i; ++k) {
add(g[i + 1][j][k], g[i + 1][j - 1][k]);
for (int l = 1; l <= k; ++l) add(g[i + 1][j][k], mul(g[i + 1][j - l][k - l], f[j - l + 1][j]));
}
if (j > m[i]) {
for (int k = 0; k <= j - 1 - i; ++k) {
add(f[i][j], mul(g[i + 1][j - 1][k], h[len - k]));
}
}
}
b[0] = 1;
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= i; ++j)
add(b[i], mul(b[i - j], f[i - j + 1][i]));
}
cout << b[n] << endl;
return 0;
}
标签:排列,OEIS,CF1874F,int,区间,长度,Jellyfish,mod
From: https://www.cnblogs.com/Tagaki-san/p/18436708