题目大意
你可以将一个排列的前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 imes (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
", kase++, ans);
}
return 0;
}