# CF1089I Interval-Free Permutations

## 本题题解

• 由两段极长不合法子段组成，这两段不合法子段可能相交。形式化地，若这两个子段分别是 $$[l_1, r_1], [l_2, r_2]$$，则 $$l_1 = 1, r_2 = n$$，且 $$r_1\geq l_2 - 1$$
• 由三段及以上的极长不合法子段拼成，它们互不相交。形式化地，若这些子段分别是 $$[l_1, r_2], [l_2, r_2], \dots [l_k, r_k]$$，则 $$l_1 = 1, r_k = n$$，且 $$\forall 1\leq i < k: r_i + 1 = l_{i + 1}$$

$f(n) = n! - 2\cdot \sum_{i = 1}^{n - 1} h(i)\cdot (n - i)! - \sum_{j = 3}^{n - 1}g(n, j)\cdot f(j)$

## 参考代码

// problem: CF1089I
#include <bits/stdc++.h>
using namespace std;

#define mk make_pair
#define fi first
#define se second
#define SZ(x) ((int)(x).size())

typedef unsigned int uint;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;

template<typename T> inline void ckmax(T& x, T y) { x = (y > x ? y : x); }
template<typename T> inline void ckmin(T& x, T y) { x = (y < x ? y : x); }

const int MAXN = 400;
int MOD;

inline int mod1(int x) { return x < MOD ? x : x - MOD; }
inline int mod2(int x) { return x < 0 ? x + MOD : x; }
inline void add(int &x, int y) { x = mod1(x + y); }
inline void sub(int &x, int y) { x = mod2(x - y); }

int fac[MAXN + 5];
int h[MAXN + 5];
int g[MAXN + 5][MAXN + 5];
int f[MAXN + 5];

void init(int n) {

fac[0] = 1;
for (int i = 1; i <= n; ++i) {
fac[i] = (ll)fac[i - 1] * i % MOD;
}

h[1] = 1;
for (int i = 2; i <= n; ++i) {
h[i] = fac[i];
for (int j = 1; j < i; ++j) {
sub(h[i], (ll)h[j] * fac[i - j] % MOD);
}
}

g[0][0] = 1;
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= i; ++j) {
for (int k = 1; k <= i; ++k) {
add(g[i][j], (ll)g[i - k][j - 1] * fac[k] % MOD);
}
}
}

f[1] = 1; f[2] = 2;
for (int i = 3; i <= n; ++i) {
f[i] = 0;
for (int j = 1; j < i; ++j) {
add(f[i], (ll)h[j] * fac[i - j] % MOD);
}
f[i] = mod1(f[i] * 2);

for (int j = 3; j < i; ++j) {
add(f[i], (ll)g[i][j] * f[j] % MOD);
}
f[i] = mod2(fac[i] - f[i]); // 总 - 不合法
}
}

int main() {
int T;
cin >> T;

cin >> MOD;
init(MAXN);

while (T--) {
int n;
cin >> n;
cout << f[n] << endl;
}
return 0;
}

posted @ 2021-03-25 23:18  duyiblue  阅读(205)  评论(0编辑  收藏  举报