• C. Cyclic Permutations


    题意:给定一个序列,我们根据这个序列来建立一张n个节点的图如下:
    1.对于1 <= i <= n,我们找到一个最大的j,满足1 <= j < i并且pj > pi,在节点i和节点j之间连一条边
    2.对于1 <= i <= n,我们找到一个最小的j,满足i < j <= n并且pj > pi,在节点i和节点j之间连一条边

    求所有序列中,满足含有简单环的情况,数据很大,需要模上1e9+7

    分析:我们先来看看样例给出的4,答案为16,全集为4 * 3 * 2 * 1,所有序列个数为24,说明不合法的情况相对于全集来说很少,说明我们可以尝试用全集-不合法的情况来算出合法的情况。我们来看看[3, 1, 2, 4],,存在简单环的情况,,从1开始到2,从2再到3,再回到1。对于题目来说,一个点会连向最靠近它的大于它的值的点,不失一般性,我们假设如下:,然后假设pi < pk,那么pi和pk之间也会连一条边,这样就存在一个简单环了。pi和pk是最靠近pj的并且大于pj的数,我们可以发现,(pi, pj),(pj, pk)之间的点都是小于左右两个端点的值的。我们可以得到不合法的情况即是一个单峰序列,单峰序列的方案数为(2^{n-1})。那么合法的方案数即为(n! - 2^{n-1})

    单峰排列的个数:假设f[i]为1~i构成的单峰排列方案数,那么我们f[i + 1]为把i + 1插入到f[i]的排列的峰顶i的左右两侧,方案数则为f[i] * 2,即f[i + 1] = f[i] * 2。

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <vector>
    #include <algorithm>
    
    using namespace std;
    using ll = long long;
    const int mod = 1e9 + 7;
    
    int qmi(int a, int b)
    {
    	int res = 1;
    	while (b)
    	{
    		if (b & 1) res = (ll)res * a % mod;
    		a = (ll)a * a % mod;
    		b >>= 1;
    	}
    	return res;
    }
    
    int main()
    {
    	int n;
    	cin >> n;
    
    	int res = 1;
    
    	for (int i = n; i >= 1; --i)
    	{
    		res = ((ll)res * i) % mod;
    	}
    
    	res = (((ll)res - qmi(2, n - 1)) % mod + mod) % mod;
    
    	cout << res << endl;
    
    	return 0;
    }
    
  • 相关阅读:
    做了一些心理学的测试,分析下个人
    做了一些心理学的测试,分析下个人
    逆转一个整数
    打印九九乘法表
    计算两个日期相差多少天
    struct的使用
    Linux Vim替换字符串的一些方法小结
    CentOS里vim基本操作
    如何创建一个后台进程
    高中是个把人分类的机器(转)
  • 原文地址:https://www.cnblogs.com/pixel-Teee/p/13468684.html
Copyright © 2020-2023  润新知