您的位置:首页 > 其它

数学专项counting:UVa 11481

2013-10-16 23:12 447 查看
题目大意就是求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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: