• P4071 [SDOI2016]排列计数 错排+组合数


    题意:

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

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

    范围&性质:(1le Tle 10^5,1le n,mle10^6)

    分析:

    前置芝士:

    错排的常见公式:

    (f_i)表示 (i) 阶排列的个数,(g_i) 表示 (i) 阶错排的个数。
    (n! = f_n =n sum C_n^igi)
    于是可以解得
    (g_i =n sum (−1)^{n−i}C_n^i fi =n sum (−1)^{n−i}C_n^i i! = n!sum_{i=0}^n frac{(-1)^i}{i!})
    由此还可以顺便求出它的递推式是:

    (g_{n+1}= (n + 1)g_n + (−1)^{n+1}) 其初值是 (g_0 = 1)


    对于这道题来说,先组合数从n个数中选择m个,再乘上错排

    代码:

    #include<bits/stdc++.h>
    
    using namespace std;
    
    namespace zzc
    {
    	const int mod = 1e9+7;
    	const int maxn = 1e6+5; 
    	int t,n,m;
    	long long inv[maxn],fac[maxn],per[maxn];
    	
    	void init()
    	{
    		inv[1]=1;
    		fac[1]=1;
    		fac[0]=1;
    		for(int i=2;i<=1000000;i++)
    		{
    			inv[i]=(mod-mod/i)*inv[mod%i]%mod;
    			fac[i]=fac[i-1]*i%mod;
    		}
    		
    		inv[0]=1;
    		for(int i=1;i<=1000000;i++)
    		{
    			inv[i]=inv[i]*inv[i-1]%mod;
    		}
    		
    		per[0]=1;
    		for(int i=1;i<=1000000;i++)
    		{
    			per[i]=(per[i-1]*i%mod+(i%2==1?-1:1))%mod;
    		}
    	}
    	
    	long long C(int a,int b)
    	{
    		return fac[a]*inv[a-b]%mod*inv[b]%mod;
    	}
    	
    	void work()
    	{
    		init();
    		scanf("%d",&t);
    		while(t--)
    		{
    			scanf("%d%d",&n,&m);
    			printf("%lld
    ",C(n,m)*per[n-m]%mod);
    		}
    	}
    	
    }
    
    int main()
    {
    	zzc::work();
    	return 0;
     } 
    
  • 相关阅读:
    Spring 事务管理
    16.04更新源
    idea操作git远程回滚到某个提交节点或某个版本
    pip下载速度慢、pip下载超时解决方案:更换pip下载源
    IntelliJ IDEA激活和配置
    docker中启动nginx
    Docker推送镜像到阿里云仓库
    docker使用Dockerfile制作tomcat镜像(实际操作没有问题)
    Linux CentOS7中端口的操作
    promiseAll使用
  • 原文地址:https://www.cnblogs.com/youth518/p/13681859.html
Copyright © 2020-2023  润新知