Accept: 31 Submit: 95
Time Limit: 1000 mSec Memory Limit : 262144 KB
Problem Description
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
Sample Output
Source
第八届福建省大学生程序设计竞赛-重现赛(感谢承办方厦门理工学院)题意:n个巫师对应n个魔法棒,问让至少k个巫师拿对自己的魔法棒有多少种重排方案;
思路:从n中选k个组合,剩下n-k个全错排;全错排公式:a[i]=(i-1)*(a[i-1]+a[i-2]); 相同思路的题目nyoj451光棍节的快乐
代码1:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define mod 1000000007
const int maxn=10004;
typedef long long ll;
ll f[maxn+10];
ll fac[maxn+10];
void init()
{
fac[0]=1,fac[1]=1,fac[2]=2; //预处理阶乘
for(ll i=3;i<=maxn;i++)
{
fac[i]=(fac[i-1]*i*1LL)%mod;
fac[i]%=mod;
}
}
ll inv(ll a) //求a对mod的逆元
{
return a==1?1:inv(mod%a)*(mod-mod/a)%mod;
}
ll C(ll n,ll m) //组合数
{
return fac[n]*inv(fac[m])%mod*inv(fac[n-m])%mod;
}
int main()
{
int T;
f[0]=1,f[1]=0,f[2]=1,f[3]=2;
for(ll i=4;i<=maxn;i++)
{
f[i]=(i-1)*((f[i-1]%mod+f[i-2]%mod)%mod);
f[i]%=mod;
}
init();
scanf("%d",&T);
while(T--)
{
ll n,k;
scanf("%I64d%I64d",&n,&k);
ll res=0;
for(int i=k;i<=n;i++)
{
ll res1=C(n,i)%mod;
ll res2=f[n-i]%mod;
// printf("%I64d %I64d\n",res1,res2);
res+=(res1*res2)%mod;
res%=mod;
}
printf("%I64d\n",res);
}
return 0;
}
//耗时109ms
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define mod 1000000007
const int maxn=10004;
typedef long long ll;
ll f[maxn+10],inv[maxn+10];
ll fac[maxn+10];
ll mod_pow(ll x,ll n)
{
ll res=1;
while(n>0)
{
if(n&1)
res=res*x%mod;
x=x*x%mod;
n>>=1;
}
return res%mod;
}
void init()
{
fac[0]=1,fac[1]=1,fac[2]=2;
for(ll i=3;i<=maxn;i++)
{
fac[i]=(fac[i-1]*i*1LL)%mod;
fac[i]%=mod;
}
inv[maxn]=mod_pow(fac[maxn],mod-2); //预处理阶乘的逆元
for(ll i=maxn-1;i>=0;i--)
inv[i]=(inv[i+1]*(i+1))%mod;
}
ll C(ll n,ll m)
{
return fac[n]*inv[m]%mod*inv[n-m]%mod;
}
int main()
{
int T;
f[0]=1,f[1]=0,f[2]=1,f[3]=2;
for(ll i=4;i<=maxn;i++)
{
f[i]=(i-1)*((f[i-1]%mod+f[i-2]%mod)%mod);
f[i]%=mod;
}
init();
scanf("%d",&T);
while(T--)
{
ll n,k;
scanf("%I64d%I64d",&n,&k);
ll res=0;
for(int i=k;i<=n;i++)
{
ll res1=C(n,i)%mod;
ll res2=f[n-i]%mod;
// printf("%I64d %I64d\n",res1,res2);
res+=(res1*res2)%mod;
res%=mod;
}
printf("%I64d\n",res);
}
return 0;
}
//耗时0ms
*因为须对1e9+7取模,所以可以先预处理阶乘数组fac[ ],阶乘的线性逆元inv[ ],如果每次都求一下c(n,i)的话,复杂度位O(n^2);
*另外求组合数是fac[n]/fac[m]/fac[n-m]这样的话,会爆精度,应该变除为乘,乘以所要除的数的逆元,所以先预处理一波阶乘的逆元;
*代码2比代码1高效在于预处理阶乘的线性逆元,预处理代码是学习别人的;