I
I
I
感觉这题非常厉害
为了方便解释,做以下约定
1.
1.
1.将全序列
p
1
,
p
2
.
.
.
p
n
p_1,p_2...p_n
p1,p2...pn记为
A
A
A
2.
2.
2.将
A
A
A的某个严格子区间记作
B
i
B_i
Bi
题目把 interval 定义为值域大小和区间大小相等的
B
i
B_i
Bi
我们定义maximal interval为不被任意一个interval完整包含的interval
有一个重要结论:如果两个maximal interval B x , B y B_x,B_y Bx,By相交,那么区间 B x ∪ B y B_x∪B_y Bx∪By一定符合interval的定义,又因为 B x , B y B_x,B_y Bx,By是maximal interval,所以若他们相交,那么并一定就是 A A A
考虑算出
n
n
n的全排列里所有不合法的排列
依据这个结论,我们可以将不合法的排列分为两类
类型
1
:
1:
1:存在两个maximal interval
B
u
,
B
v
B_u,B_v
Bu,Bv,使
B
u
∪
B
v
=
A
B_u∪B_v=A
Bu∪Bv=A
类型
2
:
2:
2:A为大于等于3个maximal interval挨着连在一起组成
我们先考虑类型
1
1
1,它可以分为
B
u
B_u
Bu和
B
v
B_v
Bv相交或相邻两种情况
若
B
u
B_u
Bu和
B
v
B_v
Bv相交,记
B
w
=
B
u
∩
B
v
,
B
u
′
=
B
u
−
B
w
,
B
v
′
=
B
v
+
B
w
B_w=B_u∩B_v,B_{u'}=B_u-B_w,B_{v'}=B_v+B_w
Bw=Bu∩Bv,Bu′=Bu−Bw,Bv′=Bv+Bw,
转化完后得到的
B
u
′
和
B
v
′
B_{u'}和B_{v'}
Bu′和Bv′是相邻的,因此我们只要考虑
B
u
,
B
v
B_u,B_v
Bu,Bv相邻的情况
显然可以发现
B
u
,
B
v
B_u,B_v
Bu,Bv的值域分别为
[
1
,
k
]
,
[
k
+
1
,
n
]
[1,k],[k+1,n]
[1,k],[k+1,n](证明可以用反证)
不妨假设
B
u
B_u
Bu在
B
v
B_v
Bv的左侧(右侧的情况方案数是相同的)
为了避免重复计数,我们强制令 B u B_u Bu的prefix中除了自己外,没有任何一个prefix满足值域为 [ 1 , k ] [1,k] [1,k]且为interval (若存在这样的prefix,可以通过上面那个相交变相邻的转化转为不存在)
那么就可以统计数量了,记
f
n
f_n
fn为
n
n
n的所有排列
A
A
A中满足 任何一个prefix都不满足值域为
[
1
,
k
]
[1,k]
[1,k]且为interval 的排列数量
有
f
n
=
n
!
−
∑
i
=
1
n
−
1
(
f
i
∗
(
n
−
i
)
!
)
f_n=n!-\sum_{i=1}^{n-1}(f_i*(n-i)!)
fn=n!−i=1∑n−1(fi∗(n−i)!)
接着考虑类型
2
2
2
对于某个maximal interval
B
u
B_u
Bu,他内部是任意排的,我们唯一要满足的限制是不存在某一段连续的maximal interval可以拼成一个interval
这个限制相当于这些maximal interval的排列是interval-free的
由于我们统计的是非法方案,因此至少存在一个maximal interval
B
v
B_v
Bv的大小是>=2的,于是这些maximal interval的个数<n,就化成了子问题
为了计算这种的方案数,需要一个辅助的dp
记
g
n
,
k
g_{n,k}
gn,k为将
n
n
n划分成
k
k
k段,每段内部任意排列的方案数
有
g
n
,
k
=
∑
i
=
k
−
1
n
−
1
g
i
,
k
−
1
∗
(
n
−
i
)
!
g_{n,k}=\sum_{i=k-1}^{n-1}g_{i,k-1}*(n-i)!
gn,k=∑i=k−1n−1gi,k−1∗(n−i)!
然后就可以算答案了,记
a
n
s
n
ans_n
ansn为
n
n
n的所有排列
A
A
A中interval-free的排列数
a
n
s
n
=
n
!
−
2
∑
i
=
1
n
−
1
f
i
∗
(
n
−
i
)
!
−
∑
k
=
3
n
−
1
g
n
,
k
∗
a
n
s
k
ans_n=n!-2\sum_{i=1}^{n-1}f_i*(n-i)!-\sum_{k=3}^{n-1}g_{n,k}*ans_k
ansn=n!−2i=1∑n−1fi∗(n−i)!−k=3∑n−1gn,k∗ansk
maya我的语言表达太差了,写的题解长度可能是原题解的2倍…
code:
#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
const int maxn = 405;
int n,mod;
inline void add(int &a,const int &b){ a+=b;if(a>=mod)a-=mod; }
inline void dec(int &a,const int &b){ a-=b;if(a<0) a+=mod; }
int s[maxn];
int f[maxn],ans[maxn];
int g[maxn][maxn];
int main()
{
//freopen("tmp.in","r",stdin);
//freopen("tmp.out","w",stdout);
int Tcase; scanf("%d%d",&Tcase,&mod);
s[0]=1; for(int i=1;i<maxn;i++) s[i]=(ll)s[i-1]*i%mod;
f[1]=1;
for(int i=2;i<maxn;i++)
{
f[i]=s[i];
for(int j=1;j<i;j++) dec(f[i],(ll)f[j]*s[i-j]%mod);
}
g[0][0]=1;
for(int i=1;i<maxn;i++) for(int j=1;j<=i;j++)
{
for(int k=j-1;k<i;k++) add(g[i][j],(ll)g[k][j-1]*s[i-k]%mod);
}
ans[1]=1;
for(int i=2;i<maxn;i++)
{
ans[i]=s[i];
for(int j=1;j<i;j++) if(i-j>1||j>1)
dec(ans[i],2ll*f[j]%mod*s[i-j]%mod);
for(int k=3;k<i;k++) dec(ans[i],(ll)g[i][k]*ans[k]%mod);
}
while(Tcase--)
{
scanf("%d",&n);
printf("%d\n",ans[n]);
}
return 0;
}
先写这么多剩下的心情好的时候填坑