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;
    }
  • 相关阅读:
    【Leetcode_easy】720. Longest Word in Dictionary
    【Leetcode_easy】717. 1-bit and 2-bit Characters
    【Leetcode_easy】709. To Lower Case
    【Leetcode_easy】707. Design Linked List
    【Leetcode_easy】706. Design HashMap
    第38课 栈和队列的相互转化
    第7章 网络层协议(4)_IGMP协议
    第7章 网络层协议(3)_ARP协议
    第33课 双向循环链表的实现
    第32课 Linux内核链表剖析
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793458.html
Copyright © 2011-2022 走看看