顺着题面来推,长度为n的数列中有m个位置不变,相当与求从n里选m个的组合数。剩余可变的位置相当于求错排。
数据范围n≤1000000,不能递推求组合数,可以直接公式计算,但同时要求逆元来支持取模运算。
因此需要递推求最大范围内的组合数和错排,两者都是线性的,所以时间复杂度都是O(1000000),每读入一组数据直接公式输出就行。
#include<cstdio>
using namespace std;
#define maxn 1000005
const long long mod=1000000007;
long long T;
long long js[maxn+5],F[maxn+5];
inline void pre_fir()
{
js[0]=1;
for(int i=1;i<=maxn;i++) js[i]=js[i-1]*i,js[i]%=mod;
F[0]=1,F[1]=0,F[2]=1;
for(int i=3;i<=maxn;i++)
{
F[i]=(i-1)*(F[i-1]+F[i-2]);
F[i]%=mod;
}
}
inline long long qpow(long long x,long long y)
{
long long ans=1;
while(y!=0)
{
if(y&1) ans=ans%mod*x%mod;
x=x%mod*x%mod;
y>>=1;
}
return ans%mod;
}
inline long long inv(long long x)
{
return qpow(x,(long long)(mod-2));
}
inline long long C(long long x,long long y)
{
return js[x]%mod*inv(js[y])%mod*inv(js[x-y])%mod;
}
int main()
{
scanf("%lld",&T);
pre_fir();
while(T--)
{
long long n,m;
scanf("%lld%lld",&n,&m);
if(m>n) printf("0
");
else printf("%lld
",C(n,m)%mod*F[n-m]%mod);
}
return 0;
}