【BZOJ 4517】排列计数 - 排列组合+乘法逆元

【题意】
求有多少种长度为 n 的序列 A,满足:
①1 ~ n 这 n 个数在序列中各出现了一次;
②若第 i 个数 A[i] 的值为 i,则称 i 是稳定的。序列恰好有 m 个数是稳定;
满足条件的序列可能很多,序列数对 10^9+7 取模。

数据范围: T=500000n1000000m1000000

【分析】
对于稳定的数,有 Cmn=n!m!(nm)! 种选择,很明显预处理出 1! n! 的值,还有 1! n! 的所有拟元即可。

对于不稳定的数,有 nm 个,这个问题等价于一个左右各有 nm 个点的二分图,现在求有多少种完备匹配,满足横向不连边。
由于最多 n 个,很明显并不需要得到封闭形式,只用得到边界和递推形式就可以了。

an表示 a 个数的满足条件的完备匹配的个数。
边界:a0=1 a1=0
递推:假设当前已经求出了 a0,a1,...,an1 ,现在要求 an
因为是完备匹配,所以 n 一定在一个连边组成的联通块之中。
枚举联通块的大小为k,则这时有Pk1n1种联通块方案。
所以 an=nk=2Pk1n1ank=nk=2(n1)!(nk)!ank
更换求和指标, an=(n1)!n2k=0akk!=[(n1)(n2)!][n3k=0akk!+an2(n2)!]=(n1)(n2)!n3k=0akk!+(n1)(n2)!an2(n2)!=(n1)an1+(n1)an2=(n1)(an1+an2)
所以用这个递推式求出所有的 a <script type="math/tex" id="MathJax-Element-66">a</script>。

【代码】

#include <cstdio>
#include <cctype>

typedef long long LL;

const int N=1000001;
const int L=1000000007;

int f[N];
int g[N],inv[N];

int cas;
int n,m;
int res;

inline int read(void)
{
    int x=0; char c=getchar();
    for (;!isdigit(c);c=getchar());
    for (;isdigit(c);c=getchar()) x=x*10+c-'0';
    return x;
}

int mi(int i,int j)
{
    if (!j) return 1;
    int mtp=mi(i,j>>1);
    mtp=(LL)mtp*mtp%L;
    if (j&1) mtp=(LL)mtp*i%L;
    return mtp;
}

int main(void)
{
//  freopen("a.in","r",stdin);
//  freopen("a.out","w",stdout);

    f[0]=1,f[1]=0;
    for (int i=2;i<N;i++)
        f[i]=((LL)f[i-1]+f[i-2])*(i-1)%L;
    g[0]=1;
    for (int i=1;i<N;i++)
        g[i]=(LL)g[i-1]*i%L;
    for (int i=0;i<N;i++)
        inv[i]=mi(g[i],L-2);

    cas=read();
    for (int cc=1;cc<=cas;cc++)
    {
        n=read(),m=read();
        if (n>=m)
            res=(LL)g[n]*inv[m]%L*inv[n-m]%L*f[n-m]%L;
        else res=0;
        //res=C(n,m)*a[n-m]= n! / m! / (n-m)! * a[n-m]
        printf("%d\n",res);
    }

    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值