uva 11481 Arrange the Numbers

链接: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]=(n-1)*(f[n-1]+f[n-2]);注意最后如果m=k,则需要加上原排列1,2,3……n(答案再加1)

代码如下:

 1 /*
 2   先这么考虑,剩下的n-k个数都错排,然后后面的n-m个数中有1个数在原位上,其余的n-k-1个数依旧错排
 3   那么答案边是C(m,k)*(f[n-k]+f[n-k-1]*C(n-m, 1) + ……+ f[1]*C(n-m, n-m)) ,其中f为错排函数 
 4 */ 
 5 #include <iostream>
 6 #include <cstdio>
 7 using namespace std;
 8 
 9 const int p = 1000000007;
10 long long f[1001], c[1001][1001];
11 int main()
12 {
13     f[1] = 0; f[2] = 1;
14     for (int i=3; i<=1000; i++) f[i] = (i-1)*(f[i-1]+f[i-2])%p;
15     c[0][0] = 1;
16     for (int i=1; i<=1000; i++)  
17     {
18         c[i][0] = 1;
19         for (int j=1; j<=i; j++) c[i][j] = (c[i-1][j] + c[i-1][j-1])%p;
20     }
21     int t; scanf("%d", &t);
22     for (int kase=1; kase<=t; kase++)
23     {
24         int n, m, k; scanf("%d%d%d", &n, &m, &k);
25         long long ans = 0;
26         for (int i=0; i<=n-m; i++)
27             ans = (ans + f[n-k-i]*c[n-m][i])%p;
28         ans = ans*c[m][k]%p;
29         if (m == k) ans = (ans+1)%p;    //此时原排列也要加上去 
30         printf("Case %d: %lld\n", kase, ans);
31     }
32     return 0;
33 }
View Code

 

posted @ 2013-08-09 21:13  sxqqslf  阅读(398)  评论(0编辑  收藏  举报