(color{Orange}{如果这篇文章有帮到你,留个言让博主开心一下吧})~(讲的可能不是很好)
(color{Red}{----------------------分割-------------------------})
(让我们一步一步慢慢来)
(举个例子,当排列长度是n时)
(考虑x和y作为某对[l,r]中的最大值和最小值,有多少排列包含这对?)
(根据题意r-l=x-y,区间长度为L=x-y+1)
(说明这个区间可以放在(n-L+1)个位置)
(然后只能用大于y小于x的数填充这个小区间)
(所以小区间的方案是L!,其他地方数可以随便放(n-L)!)
(所以,以x,y作为小区间中的max和min时)
(有(n-L+1)*(L!)*(n-L)!个排列满足要求)
(于是我们枚举x和y的值累加答案,最后加上特殊的区间长度为1的情况就是答案)
(color{Red}{如果你还没有看懂上面的意思,没关系,我们来举个例子})
(当排列长度为5时)
(我们枚举x和y,假设当前x=4,y=1)
(所以区间长度时是4,那么这个区间可以放在[1,4]和[2,5]两个地方)
(而且这个区间一定是由1,2,3,4填充,有4!种选法)
(出去这个区间外排列还有1个位置,有1!种选法)
(所以x=4,y=1时排列有2*(4!)(1!)种选法)
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxn=250009;
int n,mod,x,y,ans;
int fac[maxn];
signed main()
{
cin>>n>>mod;
fac[0]=1;
for(int i=1;i<=n;i++) fac[i]=fac[i-1]*i%mod;//求阶乘
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++)
{
int l=j-i+1;
int option=n-l+1;//区间选法
int yushu=n-l;//余下的数字随意排列
ans=(ans+option*fac[l]%mod*fac[n-l])%mod;
}
ans=(ans+fac[n]*n%mod)%mod;//加上区间长度为1的答案
cout<<ans;
}
(color{Red}{遗憾的时,O(n^2)远远不够})
(但是我们突然发现x和y的值并不重要)
(比如(4,5)和(5,6)的对数是一样的)
(所以接下来我们只枚举区间长度)
(在上面的基础上乘以区间长度为i时的选法)
(比如区间长度为2时可以选(1,2),(2,3),(3,4)等等)
(那就乘上这些区间的个数n-i+1)
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxn=250009;
int n,mod,x,y,ans;
int fac[maxn];
signed main()
{
cin>>n>>mod;
fac[0]=1;
for(int i=1;i<=n;i++) fac[i]=fac[i-1]*i%mod;//求阶乘
for(int i=1;i<=n;i++)//枚举区间长度
{
int option=n-i+1;//区间位置选法
int yushu=n-i;//剩下的数随便排列
int extra=n-i+1;//区间长度为i的有n-i+1种
ans=(ans+option*fac[i]%mod*fac[n-i]%mod*extra%mod)%mod;
}
cout<<ans;
}