FZU2282 Wand

题意

   n个数字,要求至少k个数字位置不变,其余进行错排的方案数

分析

  错排公式:

D(n)=(n-1)[D(n-2)+D(n-1)]

 果n个数字,i个数字位置不变,其余进行错排的的方案数是C(n,i)*D[n-i]

 那么题目的答案显然就是从k枚举到n,然后把所有的方案数加起来,这样显然是正确的,但是等等!这样会超时(而且也会MLE)!因为k很    小而n比较大!

 所以我们可以把问题反过来。枚举从0到k-1,把方案数加起来,再用n的全排列减去这个方案数的和,这样就可以在时间范围内解决啦

 等等,WA掉了!一脸懵逼的开始试数据。当试了一个n=13,k=1的时候发现是个负的!也就是这个错排的方案数大于了全排列的方案数,所以相减变成了负的!可是这怎么可能!

 这是可能的,因为,我们取模了!所以此时错排方案数还没有超过MOD值但是全排列超过了,所以反而全排列要小。为了解决这个我们只要在相减的时候先加上一个MOD再相减就可以了~

 

 1 #include <cstdio>
 2 #include <algorithm>
 3 #include <cstring>
 4 #include <iostream>
 5 
 6 using namespace std;
 7 const int maxn=10000+10;
 8 const int MOD=1000000007;
 9 int T,k;
10 long long n,ans;
11 long long c[maxn][105],D[maxn],A[maxn];
12 void init(){
13     D[0]=1; D[1]=0;D[2]=1;
14     for(int i=3;i<=10000;i++){
15         D[i]=((i-1)*(D[i-1]+D[i-2])%MOD)%MOD;
16     }
17     c[1][0]=1,c[1][1]=1;
18     for(int i=2;i<=10000;i++){
19         c[i][0]=1;
20         for(int j=1;j<=min(i,100);j++){
21             c[i][j]=(c[i-1][j-1]+c[i-1][j])%MOD;
22         }
23     }
24     A[1]=1;
25     for(int i=2;i<=10000;i++){
26         A[i]=(A[i-1]%MOD*i%MOD)%MOD;
27     }
28     return ;
29 }
30 int main(){
31     init();
32     scanf("%d",&T);
33     for(int t=1;t<=T;t++){
34         ans=0;
35         scanf("%lld%d",&n,&k);
36 
37         //cout<<D[n]<<endl;
38         //cout<<A[n]<<endl;
39         for(int i=0;i<k;i++){
40             int res=(c[n][i]%MOD*D[n-i]%MOD)%MOD;
41             ans=(ans+res)%MOD;
42         }
43         ans=(A[n]-ans+MOD)%MOD;
44        /* for(int i=k;i<=n;i++){
45             int res=(c[n][i]%MOD*D[n-i]%MOD)%MOD;
46             ans=(ans+res)%MOD;
47         }*/
48         printf("%lld\n",ans);
49     }
50 return 0;
51 }
52 /*
53 100
54 5 1
55 76
56 7 4
57 92
58 8 5
59 141
60 13 1
61 -63772160
62 52 10
63 273085312
64 */
View Code

 

posted @ 2018-04-21 18:29  蒟蒻LQL  阅读(290)  评论(0编辑  收藏  举报