N wizards are attending a meeting. Everyone has his own magic wand. N magic wands was put in a line, numbered from 1 to n(Wand_i owned by wizard_i). After the meeting, n wizards will take a wand one by one in the order of 1 to n. A boring wizard decided to reorder the wands. He is wondering how many ways to reorder the wands so that at least k wizards can get his own wand.
For example, n=3. Initially, the wands are w1 w2 w3. After reordering, the wands become w2 w1 w3. So, wizard 1 will take w2, wizard 2 will take w1, wizard 3 will take w3, only wizard 3 get his own wand.
Input
First line contains an integer T (1 ≤ T ≤ 10), represents there are T test cases.
For each test case: Two number n and k.
1<=n <=10000.1<=k<=100. k<=n.
Output
For each test case, output the answer mod 1000000007(10^9 + 7).
Sample Input
2 1 1 3 1
Sample Output
1 4题解:n个人排位,求至少k个人能做到自己位置的方法树。那么我们就要求出组合数Cnm,错排递推数组dp[i],然后还有数据的问题,要反向考虑,从k到n转换为从0到k(左闭右开),那么还要计算出排列递推数组fac[i](即阶乘)位总方案数,一减即得答案。
#include<iostream> using namespace std; typedef long long ll; const int maxn=10010; const int mod=1e9+7; ll C[maxn][105],dp[maxn],fac[maxn]; void Init() { fac[0]=1,fac[1]=1; for(int i=2;i<=10000;i++)//计算总方案数,即阶乘数 fac[i]=i*fac[i-1]%mod; dp[0]=1,dp[1]=0,dp[2]=1; for(int i=3;i<=10000;i++)//错排公式 { dp[i]=((i-1)*(dp[i-1]+dp[i-2])%mod)%mod;; } C[1][0]=1; C[1][1]=1; for(int i=2;i<=10000;i++)//组合公式 { C[i][0]=1; for(int j=1;j<=i&&j<=100;j++) { C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod; } } } int main() { std::ios::sync_with_stdio(0); Init(); int t,n,k; cin>>t; while(t--) { cin>>n>>k; ll ans=0; for(int i=0;i<k;i++)//由于正向考虑会T,并且k<100,那么我们反向考虑情况,用总情况减去即可 { //反向情况即为:从n个数中选取i个,剩下n-i个错排,i范围从0到k ans=(ans+(C[n][i]*dp[n-i])%mod)%mod; } cout<<(fac[n]-ans+mod)%mod<<endl;//注意输出也要取模 } return 0; }
原文地址:https://www.cnblogs.com/cherish-lin/p/10699318.html