数学专项counting:UVa 11481

来源:互联网 发布:天敏网络机顶盒说明书 编辑:程序博客网 时间:2024/06/05 07:41

题目大意就是求N个数的排列中有多少个前M个数恰有M-K个错牌。这里可以先从前M个数中选K个数不变,即C(M,K)种。然后问题就转化为求n个数前m个数错排的排列数。

递推方程为:f[i][j]=(i-j)*f[i-1][j-1]+(j-1)*f[i-1][j-2];

边界条件为:f[i][0]=i!。

#include <iostream>#include <cstdio>#include <cstring>using namespace std;typedef long long LL;const LL mod=1000000007;const int maxn=1010;LL C[maxn][maxn],dp[maxn][maxn];void init(){    memset(C,0,sizeof(C));    memset(dp,0,sizeof(dp));    C[0][0]=1;    for(int i=0;i<=1000;i++)    {        C[i][0]=C[i][i]=1;        for(int j=1;j<i;j++)            C[i][j]=(C[i-1][j]+C[i-1][j-1])%mod;    }    dp[0][0]=1;    dp[1][0]=1;dp[1][1]=0;    for(int i=2;i<=1000;i++)    {        dp[i][0]=dp[i-1][0]*i%mod;        for(int j=1;j<=i;j++)        {            dp[i][j]=(dp[i][j]+(i-j)*dp[i-1][j-1])%mod;            if(j>=2) dp[i][j]=(dp[i][j]+(j-1)*dp[i-1][j-2])%mod;        }    }}int main(){    //freopen("in.txt","r",stdin);    init();    int T,kase=1;    int n,m,k;    scanf("%d",&T);    while(T--)    {        scanf("%d%d%d",&n,&m,&k);        printf("Case %d: %lld\n",kase++,C[m][k]*dp[n-k][m-k]%mod);    }    return 0;}


原创粉丝点击