题目链接:http://acm.fzu.edu.cn/problem.php?pid=2282
编号1~n的置换,不动点个数大于等于k的方案数。
参考百度百科错排公式,可以知道长度为n,每个数都不在自己位置的方案数。然后枚举长度即可。
考虑对立面(即小于k个在自己位置的)可以优化空间。
#include<cstdio> #include<algorithm> using namespace std; const int maxn=10005; const int md=1000000007; int D[maxn]; int C[maxn][105]; int F[maxn]; int main() { D[0]=1; D[1]=0; D[2]=1; for (int i=3;i<=10000;i++) { D[i]=1ll*(i-1)*(0ll+D[i-1]+D[i-2])%md; } C[0][0]=1; for (int i=1;i<=10000;i++) { C[i][0]=1; for (int j=1;j<=min(100,i);j++) { C[i][j]=(C[i-1][j-1]+C[i-1][j])%md; } } F[0]=1; for (int i=1;i<=10000;i++) { F[i]=1ll*F[i-1]*i%md; } int t; scanf("%d",&t); while (t--) { int n,k; scanf("%d%d",&n,&k); int ans=F[n]; for (int i=0;i<k;i++) { ans=(ans-1ll*C[n][i]*D[n-i]%md+md)%md; } printf("%d ",ans); } return 0; }