给定n,k
询问有多少n
的排列满足在进行k
轮冒泡排序(这里指的是一个for
交换过去)之后形成的排列的最长上升子序列为n-1
(即只有一个数不有序)
n,k=50
(其实只有O(n)
)
这傻逼题想了一年,艹
非常显然的是,如果一个排列中的数a_i
前面有b_i(b_i0)
个数比a_i
大,那么在一轮冒泡之后,a_i
前面比a_i
大的数会少1(b_i-1)
,而a_i
也会向前前进一格(这个没啥用)
我们考虑通过b_i
来解决问题,我们先证明一下对于每个合法的b(b_ii)
,有且只有一个a
与它相对应
我们考虑怎么通过b
来推出a
非常显然a_n
可以直接通过b_n
求出,求出a_n
之后a_{n-1}
也同样求出,所以只要b
合法就有一个a
排列求出了,证毕
也就是说,对于每一次冒泡,每一个大于0
的b_i
减一,等于0
则不变
考虑什么样的终态合法:
所有
b_i=0
(即有序)中间有一段
b_i=1
,其他的都是0 比如说0 0 1 1 0(1 4 2 3 5)中间有一个
b_i!=0
,其他的都是0 比如说0 0 2 0 0(2 3 1 4 5)
这个显然是dp
过去就可以了,设3
个状态(前面全m
,处于中间段,后面全m
)
memset(dp,0,sizeof(dp)); int ans2=0; cin>>n>>m>>mod; dp[0][0]=1; for(int i=1;i<=n;i++){ if(i<=m+1){ (dp[i][0]+=dp[i-1][0]*(i))%=mod; } else{ (dp[i][0]+=dp[i-1][0]*(m+1))%=mod; (dp[i][1]+=dp[i-1][0]+dp[i-1][1])%=mod; (dp[i][2]+=dp[i-1][1]*(m+1)+dp[i-1][2]*(m+1)+dp[i-1][0]*max(0ll,i-1-(m+1)))%=mod; } } int ans=0; for(int i=0;i<3;i++)ans+=dp[n][i]; cout<<"Case #"<<ts<<": "<<ans%mod<<"\n";