洛谷 P4071 [SDOI2016]排列计数

洛谷

这是一道组合数学题。

对于一个长为n的序列,首先我们要选m个使之稳定(C^{m}_{n})

且要保证剩下的序列不稳定,即错排(D_{n-m})

所以答案就是:$$ANS=C^{m}{n}+D{n-m}$$

再看看数据范围:n最大(10^6),错排好办,直接递推:

[D[i]=(i-1)*(D[i-1]+D[i-2]) ]

D[0]=1,D[1]=0。

而组合数部分有点麻烦。$$C[i][j]=C[i-1][j]+C[i-1][j-1]$$

用上面这个公式可以做1000的点,(n^2)递推。

至于满分,我们可以用普通的组合数公式:$$C(n,m)=n!/[(n-m)!m!]$$

我们预处理ni[]表示x的阶乘。

接下来很好做了,除法取模涉及逆元,因为模数是质数,直接费马(t^{ exttt{mod}-2})

所以代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int mo=1e9+7;
int n,m;
ll D[1000001]={1,0,1},ni[1000001]={1};

void pre()
{
    for (int i=3;i<=1000000;++i)
        D[i]=(i-1)*(D[i-1]+D[i-2])%mo;
    for (int i=1;i<=1000000;++i)
        ni[i]=ni[i-1]*i%mo;
}

ll qpow(ll x)
{
    ll p=mo-2,d=1;
    while (p) {
        if (p&1) d=d*x%mo;
        x=x*x%mo;p>>=1;
    }
    return d;
}

int main()
{
    pre();
    int T;cin>>T;
    while (T--) {
        scanf("%d%d",&n,&m);
        ll C=ni[n]*qpow(ni[m]*ni[n-m]%mo)%mo;
        printf("%lld
",C*D[n-m]%mo);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/fushao2yyj/p/9513275.html