zoukankan      html  css  js  c++  java
  • 【BZOJ4517】排列计数(SDOI2016)-组合数学:错排

    测试地址:排列计数
    做法:本题需要用到组合数学中的错排问题。
    首先,如果两个序列中稳定的位置不同,那么两个序列肯定不同,因此我们枚举稳定的位置,有Cnm种方案,然后对于剩下的元素,它们不能处在编号和它相同的位置上,学过组合数学的同学应该知道这就是经典的错排问题,令长为n的排列中,对所有1in都有aii的排列数为D(n)个,我们有递推式:
    D(n)=(n1)(D(n1)+D(n2))
    边界条件为D(0)=1,D(1)=0。那么本题的答案就是CnmD(nm)
    如果只是摆递推式就太没意思了,就来讲讲这个递推式是怎么来的吧。
    我们枚举1所在的位置,显然它不可能在1号位置,那么其它任意位置它都可以选,共n1种选择。然后对于它选择的位置x,我们讨论x在不在位置1上:
    如果x在位置1上,那么其它n2个元素都不能在自己的位置上,方案数为D(n2)
    如果x不在位置1上,那么它不能在位置1,而其它n2个元素都不能在自己的位置上,方案数为D(n1)
    这就是上述递推式的由来。于是我们就解决了这一题。
    以下是本人代码:

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const ll mod=1000000007;
    int T,n[500010],m[500010],maxn=0;
    ll fac[1000010],inv[1000010],fi[1000010],D[1000010];
    
    ll C(int n,int m)
    {
        return fac[n]*fi[m]%mod*fi[n-m]%mod;
    }
    
    int main()
    {
        scanf("%d",&T);
        for(int i=1;i<=T;i++)
        {
            scanf("%d%d",&n[i],&m[i]);
            maxn=max(maxn,n[i]);
        }
    
        fac[0]=fac[1]=inv[0]=inv[1]=fi[0]=fi[1]=1;
        D[0]=1,D[1]=0;
        for(ll i=2;i<=(ll)maxn;i++)
        {
            fac[i]=fac[i-1]*i%mod;
            inv[i]=(mod-mod/i)*inv[mod%i]%mod;
            fi[i]=fi[i-1]*inv[i]%mod;
            D[i]=(i-1)*(D[i-1]+D[i-2])%mod;
        }
    
        for(int i=1;i<=T;i++)
            printf("%lld
    ",C(n[i],m[i])*D[n[i]-m[i]]%mod);
    
        return 0;
    }
  • 相关阅读:
    2016.11.9 小测试
    【noip】跟着洛谷刷noip题2
    【长沙集训】2017.10.10
    【noip】跟着洛谷刷noip题
    Oracle-函数-translate
    bit,byte,char,string区别与基本类型认识
    通俗地讲,Netty 能做什么?
    oracle判断一个字符串中是否包含另外一个字符串
    Oracle导入导出数据库(exp/imp和expdp/impdp的区别)
    同步异步以及阻塞和非阻塞的区别
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793458.html
Copyright © 2011-2022 走看看