Permutation Counting

\(n\) 的范围很小,考虑动态规划。

\(f_{i,j}\) 在前 \(i\) 个数有 \(j\)\(<\) 的个数。

\(\texttt {a<b<c<d}\),且有序列 \(a<c>b\)

  1. 若在 \(a\) 之前插入 \(d\),则变为 \(d>a<c>b\)\(<\) 个数不变。

  2. 若在 \(a<c\) 之间插入 \(d\),则变为 \(a<d>c>b\)\(<\) 个数不变。

  3. 若在 \(c>b\) 之间插入 \(d\),则变为 \(a<c<d>b\)\(<\) 个数加一。

  4. 若在 \(b\) 之后插入 \(d\),则变为 \(a<c>b<d\)\(<\) 个数加一。

所以在序列头部,\(<\) 号处加入,\(<\) 总个数不变。在序列尾部,\(>\) 号处加入,\(<\) 总个数加一。

可得转移方程:f[i][j]=(f[i-1][j]*(j+1)+f[i-1][j-1]*(i-j))

即若 \(<\) 不增加 \(f_{i,j}=f_{i-1,j}\times ( \text{原} < \text{的个数} + \text{开头的位置})\)

若增加 f[i][j]=f[i-1][j-1]*((i-1)-(j-1)-1+1); \(i-1\) 为数字个数,\(j-1\)\(<\) 号个数,数字个数减一就是符号的个数,减去 \(<\) 号个数即为 \(>\) 号个数,最后还要在加上序列末尾的 \(1\)。所以最后变为 f[i-1][j-1]*(i-j)

代码:

#include <bits/stdc++.h>
using namespace std;
const int N=1007;
const int mod=1e9+7;
long long f[N][N];
int main(){
	ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
	for(int i=1;i<N;i++){
		f[i][0]=1;
		for(int j=1;j<N;j++){
			f[i][j]=(f[i-1][j]*(j+1)+f[i-1][j-1]*(i-j))%mod;
		}
	}
	int a,b;
	while(cin>>a>>b) cout<<f[a][b]<<'\n';
	return 0;
}
posted @ 2024-04-21 21:55  shoot_down  阅读(8)  评论(0编辑  收藏  举报