zoukankan      html  css  js  c++  java
  • P4071 [SDOI2016]排列计数 题解

    原题链接

    简要题意:

    求有多少种 (1)(n) 的排列 (a),满足序列恰好有 (m) 个位置 (i),使得 (a_i = i).

    答案对 (10^9 + 7) 取模。

    分析:

    首先考虑是哪 (m) 个位置,于是这有 (dbinom{n}{m}) 种情况。

    然后就是在 (n-m) 个位置上错位排序的情况。这不就是数列 (D)

    (D(n)) 表示使得 (a_i ot = i (forall i in [1,n])) 的长度为 (n) 的排列个数。

    学过组合数学的大概都知道吧,显然我们有

    [D(n) = n D(n-1) + (-1)^n ]

    于是递推。

    组合数的话,预处理阶乘和逆元就好了。

    时间复杂度:(mathcal{O}(T log n + n)).

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N=1e6+1;
    typedef long long ll;
    const ll MOD=1e9+7;
    
    int T; ll n,m;
    ll D[N],inv[N];
    
    inline ll pw(ll x,ll y) {
    	ll ans=1; while(y) {
    		if(y&1) ans=ans*x%MOD;
    		x=x*x%MOD; y>>=1;
    	} return ans;
    }
    
    inline ll C(ll x,ll y) {
    	return inv[x]*pw(inv[y]*inv[x-y]%MOD,MOD-2)%MOD;
    }
    
    int main() {
    	scanf("%d",&T);
    	D[0]=1; inv[0]=1;
    	for(int i=1;i<N;i++) D[i]=(i*D[i-1]+pw(-1,i))%MOD;
    	for(int i=1;i<N;i++) inv[i]=inv[i-1]*i%MOD;
    	while(T--) {
    		scanf("%lld %lld",&n,&m);
    //		printf("%lld %lld
    ",C(n,m),D[n-m]);
    		printf("%lld
    ",C(n,m)*D[n-m]%MOD);
    	}
    	return 0;
    }
    
    简易的代码胜过复杂的说教。
  • 相关阅读:
    [剑指 Offer 11. 旋转数组的最小数字]
    进程描述符(PCB)
    [剑指 Offer 57. 和为s的两个数字]
    Linux netstat命令
    kafka2.3.X配置文件
    docker
    shell操作mysql数据库
    Linux文件查找之find命令
    sed 切割日志文件
    Linux文本处理之awk
  • 原文地址:https://www.cnblogs.com/bifanwen/p/15506060.html
Copyright © 2011-2022 走看看