zoukankan      html  css  js  c++  java
  • [BZOJ 4517][Sdoi2016]排列计数(组合数学/错排公式)

    Description

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

    Solution

    其实是一个裸的错排啊,用F[n]来表示n个元素的错排方案,F[n]=(n-1)*(F[n-1]+F[n-2])

    感性地理解一下这个公式大概是这样的:

    如果我们把第n个元素放在第k个位置(k有n-1种取值)

    1.把第k个元素也放在第n个位置,则有F[n-2]种方案【把剩下的元素错排】

    2.把第k个元素放在其他位置,则有F[n-1]种方案【也可以看做把1~n-1的元素错排,然后交换n和k】

    理性的证明我也不会= =

    于是这题的答案就是C(n,m)*F[n-m]

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #define Mod 1000000007
    #define MAXN 1000005
    typedef long long LL;
    using namespace std;
    int T,n,m;
    LL fac[MAXN],inv[MAXN],F[MAXN];
    int read()
    {
        int x=0,f=1;char c=getchar();
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
        return x*f;
    }
    void init()
    {
        fac[0]=1,inv[1]=1;
        for(int i=1;i<MAXN;i++)
        fac[i]=(fac[i-1]*i)%Mod;
        for(int i=2;i<MAXN;i++)
        inv[i]=((Mod-Mod/i)*inv[Mod%i])%Mod;
        inv[0]=1;
        for(int i=1;i<MAXN;i++)
        inv[i]=(inv[i]*inv[i-1])%Mod;
        F[0]=1,F[1]=0;
        for(int i=2;i<MAXN;i++)
        F[i]=((i-1)*(F[i-1]+F[i-2])%Mod)%Mod;
    }
    LL C(LL x,LL y)
    {
        if(x<y)return 0;
        return ((fac[x]*inv[y])%Mod*inv[x-y])%Mod;
    }
    int main()
    {
        T=read(),init();
        while(T--)
        {
            n=read(),m=read();
            printf("%lld
    ",(C(n,m)*F[n-m])%Mod);
        }
        return 0;
    }
  • 相关阅读:
    selenium 难定位元素、时间插件
    列表生成式
    三元表达式
    监控日志
    非空即真
    深拷贝浅拷贝
    元组
    list字典嵌套
    2021
    布尔类型
  • 原文地址:https://www.cnblogs.com/Zars19/p/6979273.html
Copyright © 2011-2022 走看看