[fzu 2282]置换不动点大于等于k的排列数

题目链接: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\n",ans);
    }
    return 0;
}

 

posted @ 2017-07-23 15:29  ACMsong  阅读(393)  评论(0编辑  收藏  举报