题目相当于让我们考虑某种排列最少能经过几次操作得到。
操作是从 1 ∼ n 1\sim n 1∼n 的顺序排列中抽取若干个元素放到排列头和尾,那么假设进行了 l l l 次操作, 1 ∼ n 1\sim n 1∼n 中还会剩下至少 n − l n-l n−l 个元素没有被抽取,也就是说这个排列的最长连续上升段长度至少是 n − l n-l n−l。
也就是说经过 l l l 次操作能得到某个排列 p p p 的必要条件是 p p p 的最长连续上升段的长度至少是 n − l n-l n−l。
显然这个条件也是充要条件:假设某个排列 p p p 的最长连续上升段的长度大于等于 n − l n-l n−l,那么我们可以通过至多 l l l 次操作就能逆推构造出操作的方法。
经过 l l l 次操作能得到某个排列 p p p 的充要条件是 p p p 的最长连续上升段的长度至少是 n − l n-l n−l。
那么题目的问题就是对于每一个 k = 0 ∼ n − 1 k=0\sim n-1 k=0∼n−1 问有多少个排列的最长连续上升段的长度至少是 n − k n-k n−k。
也等价于存在某个连续上升段长度为 n − k n-k n−k。
反过来会好计算一点:考虑有多少个排列满足该排列的每个连续上升段都小于 n − k n-k n−k,最后用 n ! n! n! 减去即可。
以下为了方便,令 k ← n − k − 1 k\gets n-k-1 k←n−k−1。
我们枚举
T
=
{
[
l
i
,
r
i
]
}
T=\{[l_i,r_i]\}
T={[li,ri]} 是排列的连续上升段的一种划分方式(即将排列划分为若干个区间
[
l
i
,
r
i
]
[l_i,r_i]
[li,ri],并且钦定所有的
[
l
i
,
r
i
]
[l_i,r_i]
[li,ri] 段内数字上升,但注意
[
l
i
,
r
i
]
[l_i,r_i]
[li,ri] 可能并不是一个极长的连续上升段),大胆假设:
A
n
s
=
∑
T
(
∏
[
l
,
r
]
∈
T
f
(
r
−
l
+
1
)
)
(
n
!
∏
[
l
,
r
]
∈
T
(
r
−
l
+
1
)
!
)
Ans=\sum_{T}\left(\prod_{[l,r]\in T}f(r-l+1)\right)\left(\dfrac{n!}{\prod\limits_{[l,r]\in T}(r-l+1)!}\right)
Ans=T∑⎝⎛[l,r]∈T∏f(r−l+1)⎠⎞⎝⎜⎛[l,r]∈T∏(r−l+1)!n!⎠⎟⎞
其中
(
∏
[
l
,
r
]
∈
T
f
(
r
−
l
+
1
)
)
\left(\prod\limits_{[l,r]\in T}f(r-l+1)\right)
([l,r]∈T∏f(r−l+1)) 是容斥系数,
(
n
!
∏
[
l
,
r
]
∈
T
(
r
−
l
+
1
)
!
)
\left(\dfrac{n!}{\prod\limits_{[l,r]\in T}(r-l+1)!}\right)
⎝⎜⎛[l,r]∈T∏(r−l+1)!n!⎠⎟⎞ 是将
1
∼
n
1\sim n
1∼n 分配给这些连续上升段的方案数。
那么接下来,我们需要构造一个容斥系数 f f f 使得上式成立。
考虑 1 ∼ n 1\sim n 1∼n 的一种排列 p p p,将它划分为若干个极长的连续上升段 T = { [ l i , r i ] } T=\{[l_i,r_i]\} T={[li,ri]}。
考虑这种排列在式子左右两边的贡献。它在等号左边的贡献是 [ max [ l , r ] ∈ T ( r − l + 1 ) ≤ k ] [\max_{[l,r]\in T}(r-l+1)\leq k] [max[l,r]∈T(r−l+1)≤k]。
考虑它在等号右边的贡献:对于任意的 [ l , r ] ∈ T [l,r]\in T [l,r]∈T,它都有可能被分为若干个小段并被统计。
我们枚举将
[
l
,
r
]
[l,r]
[l,r] 划分为若干个小段
K
[
l
,
r
]
=
{
[
l
i
′
,
r
i
′
]
}
K_{[l,r]}=\{[l'_i,r'_i]\}
K[l,r]={[li′,ri′]},那么
T
T
T 在等号右边的贡献是:
∏
[
l
,
r
]
∈
T
∑
K
[
l
,
r
]
∏
[
l
′
,
r
′
]
∈
K
[
l
,
r
]
f
(
r
′
−
l
′
+
1
)
\prod_{[l,r]\in T}\sum_{K_{[l,r]}}\prod_{[l',r']\in K_{[l,r]}}f(r'-l'+1)
[l,r]∈T∏K[l,r]∑[l′,r′]∈K[l,r]∏f(r′−l′+1)
又发现贡献只和段长
r
′
−
l
′
+
1
r'-l'+1
r′−l′+1 有关,与
l
′
,
r
′
l',r'
l′,r′ 无关,那么就相当于把
r
−
l
+
1
r-l+1
r−l+1 分解成若干个数的和。于是如果我们设
F
(
x
)
F(x)
F(x) 为
f
f
f 的 OGF,即
F
(
x
)
=
∑
i
f
(
i
)
x
i
F(x)=\sum_i f(i)x^i
F(x)=∑if(i)xi,那么:
[
max
[
l
,
r
]
∈
T
(
r
−
l
+
1
)
≤
k
]
=
∏
[
l
,
r
]
∈
T
[
x
r
−
l
+
1
]
(
∑
i
F
(
x
)
i
)
∏
[
l
,
r
]
∈
T
[
r
−
l
+
1
≤
k
]
=
∏
[
l
,
r
]
∈
T
[
x
r
−
l
+
1
]
1
1
−
F
(
x
)
\begin{aligned} \big[\max_{[l,r]\in T}(r-l+1)\leq k\big]=\prod_{[l,r]\in T}[x^{r-l+1}]\left(\sum_{i} F(x)^i\right)\\ \prod_{[l,r]\in T}[r-l+1\leq k]=\prod_{[l,r]\in T}[x^{r-l+1}]\dfrac{1}{1-F(x)} \end{aligned}
[[l,r]∈Tmax(r−l+1)≤k]=[l,r]∈T∏[xr−l+1](i∑F(x)i)[l,r]∈T∏[r−l+1≤k]=[l,r]∈T∏[xr−l+1]1−F(x)1
满足上式的一个充分条件是:
[
r
−
l
+
1
≤
k
]
=
[
x
r
−
l
+
1
]
1
1
−
F
(
x
)
1
1
−
F
(
x
)
=
∑
i
=
0
k
x
i
=
1
−
x
k
+
1
1
−
x
F
(
x
)
=
x
−
x
k
+
1
1
−
x
k
+
1
\begin{aligned} \big[r-l+1\leq k\big]&=[x^{r-l+1}]\dfrac{1}{1-F(x)}\\ \dfrac{1}{1-F(x)}&=\sum_{i=0}^kx^i=\dfrac{1-x^{k+1}}{1-x}\\ F(x)&=\dfrac{x-x^{k+1}}{1-x^{k+1}} \end{aligned}
[r−l+1≤k]1−F(x)1F(x)=[xr−l+1]1−F(x)1=i=0∑kxi=1−x1−xk+1=1−xk+1x−xk+1
于是对于每一个
k
k
k,可以使用多项式求逆
O
(
n
log
n
)
O(n\log n)
O(nlogn) 算出所有的
f
f
f。
然后再看看答案怎么推:
A
n
s
=
∑
T
(
∏
[
l
,
r
]
∈
T
f
(
r
−
l
+
1
)
)
(
n
!
∏
[
l
,
r
]
∈
T
(
r
−
l
+
1
)
!
)
=
n
!
∑
T
∏
[
l
,
r
]
∈
T
f
(
r
−
l
+
1
)
(
r
−
l
+
1
)
!
\begin{aligned} Ans&=\sum_{T}\left(\prod_{[l,r]\in T}f(r-l+1)\right)\left(\dfrac{n!}{\prod\limits_{[l,r]\in T}(r-l+1)!}\right)\\ &=n!\sum_T\prod_{[l,r]\in T}\dfrac{f(r-l+1)}{(r-l+1)!} \end{aligned}
Ans=T∑⎝⎛[l,r]∈T∏f(r−l+1)⎠⎞⎝⎜⎛[l,r]∈T∏(r−l+1)!n!⎠⎟⎞=n!T∑[l,r]∈T∏(r−l+1)!f(r−l+1)
那么如果设
G
(
x
)
G(x)
G(x) 为
f
f
f 的 EGF,就有:
A
n
s
=
n
!
[
x
n
]
(
∑
i
G
(
x
)
i
)
=
n
!
[
x
n
]
1
1
−
G
(
x
)
\begin{aligned} Ans&=n![x^n]\left(\sum_{i} G(x)^i\right)\\ &=n![x^n]\dfrac{1}{1-G(x)} \end{aligned}
Ans=n![xn](i∑G(x)i)=n![xn]1−G(x)1
于是求出
f
f
f 后也能用多项式求逆
O
(
n
log
n
)
O(n\log n)
O(nlogn) 求。总时间复杂度
O
(
n
2
log
n
)
O(n^2\log n)
O(n2logn)。
然后还有一种做法:
注意到 1 1 − x k + 1 \frac{1}{1-x^{k+1}} 1−xk+11 只有 n k + 1 \frac{n}{k+1} k+1n 项非零,乘上 x − x k + 1 x-x^{k+1} x−xk+1 之后也只有 2 n k + 1 2\frac{n}{k+1} 2k+1n 项非零,即 F ( x ) F(x) F(x) 只有 2 n k + 1 2\frac{n}{k+1} 2k+1n 非零,于是 G ( x ) G(x) G(x) 和 1 − G ( x ) 1-G(x) 1−G(x) 都只有 2 n k + 1 2\frac{n}{k+1} 2k+1n 项非零,于是暴力求 1 1 − G ( x ) \frac{1}{1-G(x)} 1−G(x)1 的复杂度为 O ( n 2 k ) O(\frac{n^2}{k}) O(kn2),那么总复杂度为 O ( ∑ k = 1 n n 2 k ) = O ( n 2 log n ) O(\sum_{k=1}^n\frac{n^2}{k})=O(n^2\log n) O(∑k=1nkn2)=O(n2logn)。那么就不用多项式求逆了。
再往下手推一下的话代码可以更加简洁,但懒得推了,就这样吧:
#include<bits/stdc++.h>
#define N 1010
using namespace std;
namespace modular
{
int mod;
inline int add(int x,int y){return x+y>=mod?x+y-mod:x+y;}
inline int dec(int x,int y){return x-y<0?x-y+mod:x-y;}
inline int mul(int x,int y){return 1ll*x*y%mod;}
inline void Add(int &x,int y){x=x+y>=mod?x+y-mod:x+y;}
inline void Dec(int &x,int y){x=x-y<0?x-y+mod:x-y;}
}using namespace modular;
inline int poww(int a,int b)
{
int ans=1;
while(b)
{
if(b&1) ans=mul(ans,a);
a=mul(a,a);
b>>=1;
}
return ans;
}
inline int read()
{
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9')
{
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
x=(x<<1)+(x<<3)+(ch^'0');
ch=getchar();
}
return x*f;
}
int n;
int fac[N],ifac[N];
int F[N],GG[N],Q[N],R[N];
//GG:1-G,Q=1/GG,R=1%GG
vector<int>v;
int main()
{
n=read(),mod=read();
fac[0]=1;
for(int i=1;i<=n;i++) fac[i]=mul(fac[i-1],i);
ifac[n]=poww(fac[n],mod-2);
for(int i=n;i>=1;i--) ifac[i-1]=mul(ifac[i],i);
for(int k=n;k>=1;k--)
{
for(int i=0;i<=n;i++) F[i]=GG[i]=Q[i]=R[i]=0;
for(int i=0;i<=n;i+=k)
{
if(i+1<=n) Add(F[i+1],1);
if(i+k<=n) Dec(F[i+k],1);
}
v.clear();
Add(GG[0],1);
for(int i=0;i<=n;i++)
{
Add(GG[i],dec(0,mul(F[i],ifac[i])));
if(GG[i]) v.push_back(i);
}
R[0]=1;
for(int i=0;i<=n;i++)
{
if(R[i])
{
Q[i]=R[i];
for(int j:v)
{
if(i+j>n) break;
Dec(R[i+j],mul(Q[i],GG[j]));
}
}
}
printf("%d\n",dec(fac[n],mul(fac[n],Q[n])));
}
return 0;
}