uva 11481 Arrange the Numbers
大意: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)
代码如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 }