• BZOJ 4517: [Sdoi2016]排列计数(组合数学)


    题面

    Description
    求有多少种长度为 n 的序列 A,满足以下条件:
    1 ~ n 这 n 个数在序列中各出现了一次
    若第 i 个数 A[i] 的值为 i,则称 i 是稳定的。序列恰好有 m 个数是稳定的
    满足条件的序列可能很多,序列数对 10^9+7 取模。
    Input
    第一行一个数 T,表示有 T 组数据。
    接下来 T 行,每行两个整数 n、m。
    T=500000,n≤1000000,m≤1000000
    Output

    输出 T 行,每行一个数,表示求出的序列数
    Sample Input
    5

    1 0

    1 1

    5 2

    100 50

    10000 5000
    Sample Output
    0

    1

    20

    578028887

    60695423

    解题思路

      题目大概就是选(m)个,其他错位排列。那么答案显然为(C_n^m*d[n-m])(d[i])表示长度为(i)的错位排列方案数,然后刚开始预处理出(d)

    代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    
    using namespace std;
    const int MAXN = 1000005;
    const int MOD = 1e9+7;
    typedef long long LL;
    
    inline int rd(){
    	int x=0,f=1;char ch=getchar();
    	while(!isdigit(ch)) {f=ch=='-'?0:1;ch=getchar();}
    	while(isdigit(ch))  {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    	return f?x:-x;
    }
    
    int T,n,m,d[MAXN],fac[MAXN],inv[MAXN];
    
    inline int fast_pow(int x,int y){
    	int ret=1;
    	for(;y;y>>=1){
    		if(y&1) ret=(LL)ret*x%MOD;
    		x=(LL)x*x%MOD;	
    	}
    	return ret;
    }
    
    inline LL C(int x,int y){
    	if(y>x) return 0;
    	return (LL)fac[x]*inv[y]%MOD*inv[x-y]%MOD;	
    }
    
    int main(){
    	d[1]=0;d[2]=1;fac[0]=1;d[0]=1;
    	for(int i=3;i<=1000000;i++) d[i]=(LL)(i-1)*(d[i-1]+d[i-2])%MOD;
    	for(int i=1;i<=1000000;i++) fac[i]=(LL)fac[i-1]*i%MOD;
    	inv[1000000]=fast_pow(fac[1000000],MOD-2);
    	for(int i=1000000-1;~i;i--) inv[i]=(LL)inv[i+1]*(i+1)%MOD;
    	T=rd();
    	while(T--){
    		n=rd(),m=rd();
    		printf("%lld
    ",(LL)d[n-m]*C(n,m)%MOD);
    	}
    	return 0;	
    }
    
  • 相关阅读:
    2.6map映照容器
    Gym
    开机提示“该站点安全证书的吊销信息不可用,是否继续?”每次开机都询问
    c++中两个类互相引用的问题
    libconfig 读取配置文件
    内存、硬盘等读取速度
    brpc 使用压缩方式传递数据
    查看系统版本
    C++ 编译出现的错误
    2021-02-06 记录大佬的直播内容
  • 原文地址:https://www.cnblogs.com/sdfzsyq/p/10056881.html
Copyright © 2020-2023  润新知