uva 1485 Permutation Counting(递推)

关键词:递推、交换法!!!、更新递推式
题意:求满足条件的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 
#include 
#include 
#include 
#include 
#include
#include
#include
#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;i5;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;
}

你可能感兴趣的:(acm_组合)