关键词:递推、交换法!!!、更新递推式
题意:求满足条件的1-n排列a[1,2…n]个数
条件:恰有k个数,满足a[i]>i
解法:递推
dp[i][j]:前i个数中恰有j个数满足a[k]>k的排列个数。
法一:
用dp[i][j]更新后面的dp值。
1第i+1个数与a[k]>k的位置上的数交换/第i+1个数位于第i+1个位置,dp值均变为dp[i+1][j] ,已知dp[i][j]个排列中恰有j个数满足a[k]>k。因此dp[i+1][j]=(j+1)*dp[i][j]
2.第i+1个数与a[k]>=k的位置上的数交换,dp值变为dp[i+1][j+1],dp[i+1][j+1]=dp[i][j]*(i-j)
法二:直接dp
方法与上述类似,考虑前i-1个元素已经排列好,将第i个元素与前面的某些元素交换
dp[i][j]=dp[i-1][j](j+1)+dp[i-1][j-1](i-j)
#include <stdio.h>
#include <string.h>
#include <set>
#include <map>
#include <algorithm>
#include<vector>
#include<complex>
#include<iostream>
#define pi acos(-1)
#define X first
#define Y second
#define ll long long
#define MP(x,y) make_pair((x),(y))
#define INF 0x3f3f3f3f
const ll mod = 1e9+7;
using namespace std ;
const ll maxn = 1000+10;
ll n,k;
ll dp[maxn][maxn];//dp[i][j]:前i个数字组成的序列中有j个满足条件的排列个数
int main(){
memset(dp,0,sizeof(dp));
dp[1][0]=1;
for(ll i=1;i<maxn-5;i++){
for(ll j=0;j<=i;j++){
dp[i+1][j]=(dp[i+1][j]+(dp[i][j]*(j+1))%mod)%mod;
dp[i+1][j+1]=(dp[i+1][j+1]+(dp[i][j]*(i-j))%mod)%mod;
}
}
while(scanf("%lld%lld",&n,&k)!=EOF){
printf("%lld\n",dp[n][k]);
}
return 0;
}