题目链接
题意:给定一个
n
n
n,对于
n
n
n的某一个排列
p
p
p,我们定义如下的连边方式将其构建为一张图:
- 对于每一个 i ∈ { 1 , 2 , 3 , . . . , n } i\in\{1,2,3,...,n\} i∈{1,2,3,...,n},分别在它左右两侧找到距离最近且比 p i p_i pi大的元素 p j p_j pj,在 i 和 j i和j i和j中间连一条无向边。如果找不到就不连。(注意是按下标连边,不是按值连边)。
简单解释一下,对于序列
p
=
[
3
,
1
,
4
,
2
]
p = [3,1,4,2]
p=[3,1,4,2],对应连出的边是
(
1
,
3
)
:
对
于
p
1
,
p
3
是
右
边
离
它
最
近
且
比
他
大
的
元
素
(1,3):对于p_1,p_3是右边离它最近且比他大的元素
(1,3):对于p1,p3是右边离它最近且比他大的元素
(
2
,
1
)
:
对
于
p
2
,
p
1
是
左
边
离
它
最
近
且
比
他
大
的
元
素
(2,1):对于p_2,p_1是左边离它最近且比他大的元素
(2,1):对于p2,p1是左边离它最近且比他大的元素
(
2
,
3
)
:
对
于
p
2
,
p
3
是
右
边
离
它
最
近
且
比
他
大
的
元
素
(2,3):对于p_2,p_3是右边离它最近且比他大的元素
(2,3):对于p2,p3是右边离它最近且比他大的元素
(
4
,
3
)
:
对
于
p
4
,
p
3
是
左
边
离
它
最
近
且
比
他
大
的
元
素
(4,3):对于p_4,p_3是左边离它最近且比他大的元素
(4,3):对于p4,p3是左边离它最近且比他大的元素
我们要做的是对于给定正整数
n
(
n
≥
3
)
n(n\ge3)
n(n≥3)的所有排列,计算生成图含环的排列数量。(至少三个点循环相连就是环了)
思路:先说答案:
n
!
−
2
n
−
1
n!-2^{n-1}
n!−2n−1
先随便考虑一个序列
[
4
,
2
,
3
,
1
,
5
,
6
]
[4,2,3,1,5,6]
[4,2,3,1,5,6],我们发现它有很多三点的环:例如
[
1
,
2
,
3
]
,
[
1
,
3
,
5
]
,
[
3
,
4
,
5
]
[1,2,3],[1,3,5],[3,4,5]
[1,2,3],[1,3,5],[3,4,5],出现这些三元环的原因是对于某个元素
i
i
i,如果它两边都建边,那必然会出现三元环,根据建边条件,也就是说对于一个元素
i
i
i,如果它的两侧均有大于
i
i
i的元素,那么必然会成环。(这挺显然的,可以随便推一推)。
因此,我们可以发现所有不成环的序列都具有峰值的性质,即元素先递增至n,再递减,我们称这类序列为单峰序列,很显然所有的单峰序列对应的图都是一颗树;(实际上利用“没有环的连通图等价于边数是n-1”的性质,我们早就可以简单的分析到这里)。因此我们只需要知道如何构造单峰序列即可,我们可以将
n
,
n
−
1
,
.
.
.
,
3
,
2
,
1
n,n-1,...,3,2,1
n,n−1,...,3,2,1依次加入双端队列来构造所有的单峰序列.例如
[
1
,
3
,
4
,
2
]
[1,3,4,2]
[1,3,4,2]就是先将
4
,
3
4,3
4,3放队头,再把2放队尾,再把1放队头。对于除了
n
n
n以外的所有元素,均可选择放入队头或队尾,即
2
n
−
1
2^{n-1}
2n−1种排列方式。
故答案为
n
!
−
2
n
−
1
n!-2^{n-1}
n!−2n−1
复杂度:
O
(
n
)
O(n)
O(n)
AC代码:
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1e6 + 10;
ll a[N];
int main() {
ll n;
ll x =2, y = 2;
cin >> n;
for (ll i = 3; i <= n; i++) {
x=(x*i)%(1000000007);
y=(y*2)%(1000000007);
a[i] = (x - y+(1000000007)) % (1000000007);
}
cout << a[n] << endl;
return 0;
}