题目链接:https://codeforces.com/contest/1091/problem/D
分两种情况讨论
情况一:
那一段本身自己就是一个\(1 \to n\)的排列,这样的情况显然有
\[n!\]
种,直接算即可。
情况二:
那一段跨越了两段,枚举它在后面那段的长度\(i\),方案数是
\[C_{n}^{i} \times i! \times ((n-i)!-1)\]
因为我们要先从\(n\)个数中选\(i\)个放在后面那段里,然后这\(i\)个数随便排列,然后前面\(n-i\)个数有\((n-i)!\)种排法,相邻的只有\((n-i)!-1\)组。
预处理阶乘和其逆元。
时间复杂度\(O(n)\),空间复杂度\(O(n)\)。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <iomanip>
using namespace std;
typedef long long ll;
const int MAXN = 1000005;
const ll MOD = 998244353;
int n;
ll ans;
ll fac[MAXN];
ll inv[MAXN];
ll power(ll a,ll b)
{
ll res = 1;
while (b)
{
if (b & 1)
res = res * a % MOD;
a = a * a % MOD;
b >>= 1;
}
return res;
}
ll C(int x,int y)
{
return fac[x] * inv[y] % MOD * inv[x - y] % MOD;
}
int main()
{
cin >> n;
fac[0] = 1;
for (int i = 1;i <= n;i++)
fac[i] = fac[i - 1] * i % MOD;
inv[n] = power(fac[n],MOD - 2);
for (int i = n;i >= 1;i--)
inv[i - 1] = inv[i] * i % MOD;
ans = fac[n];
for (int i = 1;i < n;i++)
(ans += C(n,i) * fac[i] % MOD * (fac[n - i] - 1)) %= MOD;
cout << ans << endl;
return 0;
}