C. New Year and Permutation(排列组合循序详解)

(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;
} 
原文地址:https://www.cnblogs.com/iss-ue/p/12904334.html