Permutation Counting
\(n\) 的范围很小,考虑动态规划。
\(f_{i,j}\) 在前 \(i\) 个数有 \(j\) 个 \(<\) 的个数。
若 \(\texttt {a<b<c<d}\),且有序列 \(a<c>b\)。
-
若在 \(a\) 之前插入 \(d\),则变为 \(d>a<c>b\),\(<\) 个数不变。
-
若在 \(a<c\) 之间插入 \(d\),则变为 \(a<d>c>b\),\(<\) 个数不变。
-
若在 \(c>b\) 之间插入 \(d\),则变为 \(a<c<d>b\),\(<\) 个数加一。
-
若在 \(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;
}