B3901 星空 [Easy Version]

· · 题解

题目传送门

因此,我们只需要考虑重排后最大值与相邻位置的和是否合法。 枚举最大值所在的位置 $i$,枚举与之相邻的元素对应着数组里哪两个元素。 分析之后得到有两种情况:$1<i<n$ 和 $i=1$ 或 $i=n$。 在 $i=1$ 或 $i=n$ 时,只有当 $a_j+a_{max}\le x$ 时合法。 如果合法,那么剩下的 $n-2$ 个位置可以随意地填充剩下来的元素,共有 $(n-2)!$ 种方案。 $1<i<n$,此时与最大值相邻的有两个位置。分别枚举这个位置填放了 $a_j$ 和 $a_k(≠a_{max})$。 这个数只有当 $a_j+a_{max}\le x$ 且 $a_k+a_{max}\le x$ 时合法。 如果合法,那么剩下的 $n-3$ 个位置可以随意地填充剩下来的元素,共有 $(n-3)!$ 种方案。 这道题的数据范围很小,因此无论怎么写,都能通过本题,复杂度 $O(n)$。 ```cpp //j[i]表示i的阶乘 //a[i]表示数组里的数 const int mod=1e9+7; long long n,x,mx,sum,ans,a[100005],j[100005]; int main(){ cin>>n>>x; for(int i=1;i<=n;++i)cin>>a[i]; for(int i=1;i<=n;++i)if(a[i]>mx)mx=a[i]; for(int i=1;i<=n;++i) if(a[i]!=mx&&a[i]+mx<=x)sum++; j[1]=1; for(int i=2;i<=n;++i)j[i]=(j[i-1]*i)%mod; for(int i=1;i<=n;++i){ if(i==1||i==n)ans=(ans+sum*j[n-2])%mod; else ans=(ans+sum*(sum-1)*j[n-3])%mod; } cout<<ans; return 0; } ``` 请各位大佬多多指教,如有不足请提出!