对于每个
i,如果存在这样的
q和
w
q是i左边第一个比ai大的下标
w是i右边第一个比ai大的下标
那么容易证明q和w有边,也就是构成了环
证明
因为(q,i]中没有比ai大的,[i,w)中没有比ai大的
而aq和aw就是[q,w]中最大和次大,必定连边
证毕
Ⅰ.方法一:组合构造
但是直接考虑存在环的情况比较复杂,考虑不存在环的情况
不存在环,就是对于每个
i不能同时向左右连边
也就是有么只有左边有数比它大,要么只有右边有数比它大
换言之就是要么左边都比自己小,要么右边都比自己小
这其实构成了一个单峰函数
前面一直递增到峰值
n,后面一直递减
Ⅱ.方法二:思维,图
注意到这样一个事实,除了n这个特殊的数
其他数都有比自己大的数,也就是一定会至少往外连一条边
这样就就必定会连n−1条边,构成一颗树
在树的基础上,无论多加任何一条边都会形成环
那么想构成树,每个数比自己大的数都落在自己的一侧(保证只向一侧连边)
再次得到结论,前面递增到n,后面递减
于是你可以写出这样一个程序计算
fac[0]=1;
int ans=0;
for(int i=1;i<=n;i++) fac[i]=fac[i-1]*i%mod;//阶乘
for(int i=1;i<=n;i++)//枚举n放在第i个位置
{
//c是组合数
int temp= c(n-1,i-1)%mod;//那么从剩下的n-1个数选i-1个递增放到前面,剩下的数递减放到后面
ans=(ans+temp)%mod;
}
这样当然能过,但是还是讲一下另一种方法
对于[1,n−1]每个元素,都有两种选择
把这个数放在n前面或者放在后面
所以直接是2n−1种无环的放法
那么有环方法就是n!−2n−1
(感觉讲的还算详细,给个赞嘛(不然下次没动力写了呜呜))
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int mod=1e9+7;
char a[109][109];
int fac[1000009];
int quick_pow(int x,int n)
{
int ans=1;
while( n )
{
if( n&1 ) ans=ans*x%mod;
n>>=1;
x=x*x%mod;
}
return ans;
}
int c(int n,int m)
{
if( m==0 ) return 1;
return fac[n]*quick_pow(fac[n-m]*fac[m]%mod,mod-2)%mod;
}
signed main()
{
int n;
cin >> n;
fac[0]=1;
int ans=0;
for(int i=1;i<=n;i++) fac[i]=fac[i-1]*i%mod;
for(int i=1;i<=n;i++)
{
int temp= c(n-1,i-1)%mod;
ans=(ans+temp)%mod;
}
cout << (fac[n]-ans+mod)%mod;
}