Gym - 101955C Insertion Sort(思维)

题目链接

题目大意

  你可以将一个排列的前k个数字按升序排序,有多少种长度为n的排列满足其的lis的长度至少为n-1。

解题思路

  将原来的排列按升序排序。然后通过置换其中的数来考虑方案数。
  首先如果前面k个数字都是1-k,那么后面n-k个数字的lis的长度只要不小于n-k-1就行了,而n-k个数字lis长度为n-k的只有1种,长度为n-k-1的有\((n-k-1)^2\)种。
  第二种情况是对于一个前k个数字都是1-k的排列,从前面k个数字中任意取出一个数字放到后面n-k个数字后面,这样如果排列的lis的长度为n-1的话,后面n-k个数字必须都是升序排列的,所以就有\(k\times (n-k)\)种。
  第三种情况和第二种类似,这次是从后面n-k个数字中取出一个放到前面k个里头,排好之后就只能放在第k个位置,而且必须后面n-k个数字是按升序排列的才可以,这样的情况一共有n-k种。但是有一种情况重复了,如果把n-k个数字中的第一个数字放到第k个位置的话,和把第k个数字插入到第n-k个数字后面的情况其实是一样的,还要减一,所以方案数是n-k-1。
  因为之前的情况都是考虑前k个已经排好的情况下,因为我们能对前k个排序,前k个数字可以是任意顺序,所以总的方案数就是把上面的所有情况加起来乘上\(k!\)

代码

int main() {	
	int __; cin >> __;
	int kase = 1;
	while(__--) {
		ll n, k, q; cin >> n >> k >> q;
		ll f = 1;
		k = min(n, k);
		for (ll i = 1; i<=k; ++i) f = f*i%q;
		ll ans = f*((1 + (n-k-1)*(n-k-1)%q + k*(n-k)%q+ n-k-1)%q)%q;
		printf("Case #%d: %lld\n", kase++, ans);
	}
	return 0;
} 
posted @ 2021-03-01 20:12  shuitiangong  阅读(101)  评论(0编辑  收藏  举报