题解:P17394 [ICPC 2018 Shenyang R] Insertion Sort
神秘原题大赛 T1,赛时瞪眼找的规律,现在证明一下。
一个排列的最长上升子序列长度至少为
考虑固定
- 当
n=k 时,显然这k 个元素最终会从小到大排列,原始排列可以随便放,答案就是k! 。 - 当
n=k+1 时,我们可以把新加入的k+1 放到排列末尾,方案数与n=k 的答案一致为k! ;也可以从前k 个元素中选出一个错位数插到末尾,k+1 则被挤入前k 个位置参与排序操作,方案数为k!\times k 。总的答案就是k!+(k!\times k) 。 - 当
n=k+2 时,我们还是可以把新加入的k+2 放到排列末尾,方案数与n=k+1 一致为k!+k!\times k ;也可以从前k+1 个元素中选出一个错位数插到末尾,k+2 则被推入k+1 的位置,方案数为k!\times (k+1) ;我们发现,前面的两种情况都不能让k+2 进入前k 个位置,如果我们把k+2 插到前k 个位置当作错位数,就又多了k! 个方案。总的答案就是k!+k!\times k+(k!\times k+2k!) 。 - 当
n=k+3 时,除了把k+3 放在末尾,也可以把前k+2 个元素中选出一个错位数插到末尾,k+3 则被推入k+2 的位置,方案数为k!\times (k+2) ;也可以把k+3 插在k+1 的位置上当作错位数,方案数为k! ;同理,把k+3 插到前k 个位置当作错位数,方案数也是k! 。总的答案就是k!+k!\times k+k!\times k+2k!+(k!\times k+4k!) 。 - 当
n=k+i 时,我们的答案就是n=k+i-1 的答案加上\bigl(k! \times (k+i-1) + k! \times (i-1)\bigr) ,i 每增加1 ,这个值就增加2k! 。
综上所述,每次我们求一遍阶乘,递推记录上一个答案与偏移量即可,时间复杂度
#include<bits/stdc++.h>
using namespace std;
int T,n,k,q,fac;
int main(){
cin>>T;
for(int t=1;t<=T;t++){
cin>>n>>k>>q;
k=min(n,k),fac=1;
for(int i=1;i<=k;i++)fac=1ll*fac*i%q;
int ans=fac,del=1ll*fac*k%q;
for(int i=k+1;i<=n;i++)ans=(ans+del)%q,del=(del+2*fac%q)%q;
cout<<"Case #"<<t<<": "<<ans<<'\n';
}
return 0;
}