CF1874F Jellyfish and OEIS

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;
}

posted @ 2024-09-27 22:25  Tagaki  阅读(80)  评论(0)    收藏  举报