题意:给定一个序列,我们根据这个序列来建立一张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;
}