题意
给定 \(n,k\),求满足
\[\forall i > k, p_i > \min_{j=n-k}^{n-1} p_j
\]
的排列 \(p\) 的数量。
sol
首先考虑 \(1\),容易发现,当 \(1\) 位于 \(p_k\) 之后时,永远无法满足条件,因此必须要放到 \(k\) 的左侧,而当放置了 \(1\) 以后,右侧最小的数又会成为新的 "\(1\)",因此会变为新的子任务。假设 \(1\) 被放在了 \(x\) 的位置,那么左侧方案数即为 \(A_{n-1}^{x-1}=\dfrac{(n-1)!}{(n-x)!}\),设 \(f_i\) 表示长度为 \(i\) 的子任务,则
\[f_i=\sum_{j=1}^{\min\{i, k\}}\dfrac{(i-1)!\cdot f_{i-j}}{(i-j)!}=(i-1)!\sum_{j=1}^{\min\{i, k\}}\dfrac{f_{i-j}}{(i-j)!}
\]
前缀和优化即可
代码
#include <iostream>
#include <algorithm>
#include <cstring>using namespace std;
typedef long long LL;const int N = 10000005, mod = 998244353;int f[N], factor[N], inv[N];
int n, k;
int sum[N];int qpow(int a, int k, int p){int ans = 1;while (k) {if (k & 1) ans = (LL) ans * a % p;a = (LL) a * a % p;k >>= 1;}return ans;
}int main(){scanf("%d%d", &n, &k);factor[0] = 1, sum[0] = 1;for (int i = 1; i <= n; i ++ ) factor[i] = (LL) factor[i - 1] * i % mod;inv[n] = qpow(factor[n], mod - 2, mod);for (int i = n - 1; i >= 0; i -- ) inv[i] = (LL) inv[i + 1] * (i + 1) % mod;for (int i = 1; i <= n; i ++ ){f[i] = (f[i] + (LL) factor[i - 1] * ((sum[i - 1] - ((i - k - 1) < 0 ? 0 : sum[i - k - 1])) % mod + mod) % mod) % mod;sum[i] = (sum[i - 1] + (LL) f[i] * inv[i] % mod) % mod;}printf("%d\n", f[n]);
}