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;
    }
    
    简易的代码胜过复杂的说教。
  • 相关阅读:
    C++基类的析构函数定义为虚函数的原因
    android的学习网站
    QT显示url图片
    Ubuntu安装JDK
    linux下打包压缩和解压命令
    嵌入式目录
    QT pri 文件的作用
    QT pro文件详细写法+实例
    Computer(树的直径做法)
    树的直径
  • 原文地址:https://www.cnblogs.com/bifanwen/p/15506060.html
Copyright © 2011-2022 走看看