CF1391-Codeforces Round #663 (Div. 2)-1391C - Cyclic Permutations【思维、构造】

题目链接
题意:给定一个 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 ij中间连一条无向边。如果找不到就不连。(注意是按下标连边,不是按值连边)。

简单解释一下,对于序列 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):p1p3
( 2 , 1 ) : 对 于 p 2 , p 1 是 左 边 离 它 最 近 且 比 他 大 的 元 素 (2,1):对于p_2,p_1是左边离它最近且比他大的元素 (2,1):p2p1
( 2 , 3 ) : 对 于 p 2 , p 3 是 右 边 离 它 最 近 且 比 他 大 的 元 素 (2,3):对于p_2,p_3是右边离它最近且比他大的元素 (2,3):p2p3
( 4 , 3 ) : 对 于 p 4 , p 3 是 左 边 离 它 最 近 且 比 他 大 的 元 素 (4,3):对于p_4,p_3是左边离它最近且比他大的元素 (4,3):p4p3

我们要做的是对于给定正整数 n ( n ≥ 3 ) n(n\ge3) n(n3)的所有排列,计算生成图含环的排列数量。(至少三个点循环相连就是环了)
思路:先说答案: n ! − 2 n − 1 n!-2^{n-1} n!2n1
先随便考虑一个序列 [ 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,n1,...,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} 2n1种排列方式。
故答案为 n ! − 2 n − 1 n!-2^{n-1} n!2n1
复杂度: 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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值