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

    题目链接

    Solution [SDOI2016]排列计数

    题目大意:问有多少个(1-n)的排列(A)恰好有(m)个数满足(A_i=i)

    错排,计数


    分析:

    首先我们选(m)个数有(C_n^m)种,那么我们要求答案合法就必须使得剩下的数都不满足(A_i=i),也就是我们要求(n-m)个数错排的方案数,假设(D_n)表示(n)个数错排的方案数,我们的答案就是(C_n^m imes D_{n-m})

    关键是(D)的求法,对于一个位置(n)有两种可能,前(n-1)个位置都错了,前(n-1)个位置有一个是对的,这两种情况都可以通过一次交换得到全错排情况,其它情况不行

    因此(D_n=(n-1) imes(D_{n-1}+D_{n-2}))

    预处理一下阶乘及其逆元,和错排数(D)即可

    注意当(n=m)时答案为(1)

    #include <cstdio>
    using namespace std;
    const int mod = 1e9 + 7,maxn = 1e6;
    typedef long long ll;
    ll D[maxn + 100],fac[maxn + 100],facinv[maxn + 100];
    inline ll mul(ll a,ll b){return a * b % mod;}
    inline ll qpow(ll a,ll b){
    	ll res = 1,base = a % mod;
    	while(b){
    		if(b & 1)res = mul(res,base);
    		base = mul(base,base);
    		b >>= 1;
    	}
    	return res;
    }
    inline ll inv(ll x){return qpow(x,mod - 2);}
    inline ll C(ll n,ll m){return mul(fac[n],mul(facinv[m],facinv[n - m]));}
    inline void init(){
    	fac[0] = 1,facinv[0] = 1;
    	for(int i = 1;i <= maxn;i++){
    		fac[i] = mul(fac[i - 1],i);
    		facinv[i] = inv(fac[i]);
    	}
    	D[0] = D[2] = 1;
    	for(int i = 3;i <= maxn;i++)
    		D[i] = mul(i - 1,D[i - 1] + D[i - 2]);
    }
    int t,n,m;
    int main(){
    	init();
    	scanf("%d",&t);
    	for(int i = 1;i <= t;i++)
    		scanf("%d %d",&n,&m),printf("%lld
    ",mul(C(n,m),D[n - m]));
    	return 0;
    }	
    
    
  • 相关阅读:
    [LeetCode] Strobogrammatic Number III
    [LeetCode] Strobogrammatic Number II
    [Codeforces 1253E] Antenna Coverage
    [CodeForces 466C] Number of Ways
    UVa 806 四分树
    Uva 1572 自组合
    UVa Sculpture(离散化 floodfill)
    Uva 4916 Selling Cells(随机算法)
    UvaLive 4863 Balloons(贪心)
    UvaLive 4872 Underground Cables (最小生成树)
  • 原文地址:https://www.cnblogs.com/colazcy/p/11841627.html
Copyright © 2011-2022 走看看