题目大意
求有多少长度为$n$的序列$A$,满足以下条件:
① $[1,n]$这$n$个数在序列中各出现了一次。
② 若第$i$个数$A[i]$的值为$i$,则称$i$是稳定的。序列恰好有$m$个数是稳定的。
满足条件的序列可能很多,序列数对$10^9+7$取模。
题目分析
简单的计数问题。
对于“稳定的”数,可以使用组合数计算。
对于“不稳定的”数,可以使用错排计数。
两者相乘即可得到合法序列个数。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| #include<algorithm> #include<iostream> #include<iomanip> #include<cstring> #include<cstdlib> #include<climits> #include<vector> #include<cstdio> #include<cmath> #include<queue> using namespace std;
typedef long long LL;
inline const LL Get_Int() { LL num=0,bj=1; char x=getchar(); while(x<'0'||x>'9') { if(x=='-')bj=-1; x=getchar(); } while(x>='0'&&x<='9') { num=num*10+x-'0'; x=getchar(); } return num*bj; }
const int maxn=1000000; const LL mod=1e9+7;
int t; LL fac[maxn+5],f[maxn+5],inv[maxn+5];
LL Quick_Pow(LL a,LL b) { LL sum=1; for(; b; b>>=1,a=a*a%mod)if(b&1)sum=sum*a%mod; return sum; }
LL C(LL n,LL m) { return fac[n]*inv[m]%mod*inv[n-m]%mod; }
int main() { fac[0]=f[0]=inv[0]=1; for(int i=1; i<=maxn; i++) { fac[i]=fac[i-1]*i%mod; inv[i]=Quick_Pow(fac[i],mod-2); f[i]=(i-1)*(f[i-1]+f[i-2])%mod; } t=Get_Int(); while(t--) { int n=Get_Int(),m=Get_Int(); printf("%lld\n",C(n,m)*f[n-m]%mod); } return 0; }
|