[cf 1091D]D. New Year and the Permutation Concatenation

题意:给n!个n的排列,按字典序从小到大连成一条序列,例如3的情况为:[1,2,3, 1,3,2, 2,1,3 ,2,3,1 ,3,1,2 ,3,2,1],问其中长度为n,且和为sum=n*(n+1)/2的序列有多少个?
(题意来自于:https://www.cnblogs.com/pkgunboat/archive/2018/12/31/10201676.html @维和战艇机,感谢你这么好的总结方式,借用一下希望不要介意)

思路(非官方题解):官方题解下面有种方法是:There is also a simple recurrence counting the same answer, found by arsijo:d(n)=(d(n−1)+(n−1)!−1)⋅n,我比赛时是用这个方法。

如官方题解思路,有两种n长度的子序列符合和为n*(n-1)/2:
第一种为n!个组成序列的排列;
第二种为一部分在一个排列中,另一部分在下一个排列中的排列。
显而易见,第一种有n!种情况,那下面来推第二种:

对于一个n长度的排列,假设我们先固定前k个元素,那么对于包含这些前k个元素固定的片段,是一系列①前k个元素固定;②后n-k个元素按照字典序从小到大的排列连接而成的,假设这一系列排列的数量为m。

发现这个有什么用呢?现在取出上面那段片段,我们来寻找里面排列为③使用一个排列后n-k个元素④使用下一个排列前k个元素的排列的数量,在上面片段中,能找到的排列都满足,而又由于这些排列夹在上面排列两两之间,可得数量为m-1。(就像对于一个队伍的小朋友,假设两两之间插入一个小朋友,那么插入小朋友的数量为原队伍小朋友的数量-1)。
那么有没有漏网之鱼呢?答案是没有。这个草稿纸上画下,你就明白了。m中满足条件的有m-1种,说明只有一种是不满足的。对于假设考虑只满足③的,那么片段的第一个排列是不满足的,考虑只满足④的话,片段的最后一个排列是不满足的。就不展开了。(不会暴露楼主不想打,,,咔咔)
无图片描述,emm以防卡在奇怪的地方,给上面解释一个应该不会有用的提示吧
现在还有一个问题,就是m未知,现在来求m:
由①,则有A(n,n-k)种;
而对于①的每种情况
由②,有k!种,又由解释需要-1,则有(k!-1)种情况。
至此可以得到一个重要的信息,列为**(③使用一个排列后n-k个元素④使用下一个排列前k个元素)**的排列的数量 = A(n,n-k)*(k!-1)。

知道上述公式后,来求答案:
k∈[1,n];
当k=n时,其实就是组成序列的排列,所以用组成序列排列的公式:n!;
当k!=n时,用上面得出的公式A(n,n-k)*(k!-1);
因此答案是n!+∑(k from 1 to n-1) [A(n,n-k)×(k!-1)]。

#include<stdio.h>
typedef long long ll;
const int maxn = 1e6 + 5;
const ll Mod = 998244353;
	ll a,jie[maxn],djie[maxn],n,res; //jie,djie分别是阶乘和A(n,n-k),res是结果
	
int main()
{
	scanf("%I64d",&n);
	jie[0] = 1; djie[0] = 1;
	for(a = 1;a <= n;a ++)
	{
		jie[a] = jie[a-1] * a % Mod;
		djie[a] = djie[a-1] * (n+1-a) % Mod;		
	}
	res = jie[n];
	for(a = 2;a <= n-1;a ++)
		res = (res + (jie[a] - 1) * djie[n-a] % Mod) % Mod;
	printf("%I64d\n",res);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/aiqiyizz/article/details/85530211