您的位置:首页 > 其它

uva 11481 Arrange the Numbers

2013-08-09 21:13 330 查看
链接:http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=24&page=show_problem&problem=2476

大意:1~n的排列中前m个数中恰好有k个数在原位上的个数

解法:首先是从m个数中取出k个数:C(m, k) ;其次,为了保证前m个数中剩下的m-k个数不在原位上,考虑剩下n-k个数的错排;接着是后面n-m个数中有1个在原位上,剩余n-k-1再错排C(n-m,1)*f[n-k-1],这样依次下去……结果便为:C(m,k)*(f[n-k]+f[n-k-1]*C(n-m, 1) + ……+ f[1]*C(n-m, n-m)),当然还要预处理组合数,因为有取模,所以不能用递推式C(n,m) = C(n,m-1)*(n+m-1)/m,应当采用C(n,m) = C(n-1,m)+C(n-1,m-1);错排递推式为f
=(n-1)*(f[n-1]+f[n-2]);注意最后如果m=k,则需要加上原排列1,2,3……n(答案再加1)

代码如下:

/*
先这么考虑,剩下的n-k个数都错排,然后后面的n-m个数中有1个数在原位上,其余的n-k-1个数依旧错排
那么答案边是C(m,k)*(f[n-k]+f[n-k-1]*C(n-m, 1) + ……+ f[1]*C(n-m, n-m)) ,其中f为错排函数
*/
#include <iostream>
#include <cstdio>
using namespace std;

const int p = 1000000007;
long long f[1001], c[1001][1001];
int main()
{
f[1] = 0; f[2] = 1;
for (int i=3; i<=1000; i++) f[i] = (i-1)*(f[i-1]+f[i-2])%p;
c[0][0] = 1;
for (int i=1; i<=1000; i++)
{
c[i][0] = 1;
for (int j=1; j<=i; j++) c[i][j] = (c[i-1][j] + c[i-1][j-1])%p;
}
int t; scanf("%d", &t);
for (int kase=1; kase<=t; kase++)
{
int n, m, k; scanf("%d%d%d", &n, &m, &k);
long long ans = 0;
for (int i=0; i<=n-m; i++)
ans = (ans + f[n-k-i]*c[n-m][i])%p;
ans = ans*c[m][k]%p;
if (m == k) ans = (ans+1)%p;    //此时原排列也要加上去
printf("Case %d: %lld\n", kase, ans);
}
return 0;
}


View Code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: