题面
题解
令(f_i)表示(i)个数的排列,最大的数填在了最后一个位置,且这个( ext{fast_max})函数尚未返回的方案数。
枚举数(i-1)的位置,那么(i-1)必然填在区间([i-k,i-1])内,否则函数就会返回。
那么我们有
[egin{aligned}
f_i&=sum_{j=i-k}^{i-1}f_j imes (i-j-1)! imes {j-1 choose i - 2}\
&=sum_{j=i-k}^{i-1}frac{(i-2)!}{(j-1)!}f_j
end{aligned}
]
你记一个(frac{f_j}{(j-1)!})的前缀和就可以(O(n))求出所有(f)了。
最后算答案你就枚举最大数所在位置然后和算(f)的原理相同,就是
[Ans=sum_{i=1}^nf_i imes {n-1choose i-1} imes (n-i)!
]
代码
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
const int Mod = 1e9 + 7;
const int MAX_N = 1e6 + 5;
int fpow(int x, int y) {
int res = 1;
while (y) {
if (y & 1) res = 1ll * res * x % Mod;
x = 1ll * x * x % Mod;
y >>= 1;
}
return res;
}
int N, K, fac[MAX_N], ifc[MAX_N];
int f[MAX_N], s[MAX_N];
int main () {
#ifndef ONLINE_JUDGE
freopen("cpp.in", "r", stdin);
#endif
cin >> N >> K;
fac[0] = 1; for (int i = 1; i <= N; i++) fac[i] = 1ll * fac[i - 1] * i % Mod;
ifc[N] = fpow(fac[N], Mod - 2);
for (int i = N - 1; ~i; i--) ifc[i] = 1ll * ifc[i + 1] * (i + 1) % Mod;
f[1] = s[1] = 1;
for (int i = 2; i <= N; i++) {
f[i] = 1ll * fac[i - 2] * (s[i - 1] - s[max(0, i - K - 1)] + Mod) % Mod;
s[i] = (s[i - 1] + 1ll * f[i] * ifc[i - 1]) % Mod;
}
int ans = (fac[N] - 1ll * s[N] * fac[N - 1] % Mod + Mod) % Mod;
printf("%d
", ans);
return 0;
}