zoukankan      html  css  js  c++  java
  • BZOJ4517 [Sdoi2016]排列计数 【组合数 + dp】

    题目

    求有多少种长度为 n 的序列 A,满足以下条件:
    1 ~ n 这 n 个数在序列中各出现了一次
    若第 i 个数 A[i] 的值为 i,则称 i 是稳定的。序列恰好有 m 个数是稳定的
    满足条件的序列可能很多,序列数对 10^9+7 取模。

    输入格式

    第一行一个数 T,表示有 T 组数据。
    接下来 T 行,每行两个整数 n、m。
    T=500000,n≤1000000,m≤1000000

    输出格式

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

    输入样例

    5

    1 0

    1 1

    5 2

    100 50

    10000 5000

    输出样例

    0

    1

    20

    578028887

    60695423

    题解

    考虑哪些位置是稳定的,剩余位置就不能稳定
    我们设(f[i])表示(i)个数都不稳定的方案数
    那么(ans = C_{n}^{m} * f[n - m])

    我们预处理阶乘和(f[i])就可以了

    对于(f[i]),我们考虑第(i)个数放哪,显然有(i - 1)个位置可以放
    放完后剩余(i - 1)个数和(i - 1)个位置,其中有一个位置都可以放,有一个数的位置被占了,所以可以任意放

    那我们设(g[i])表示这种情况下的方案数,如果我们称那个可以任意放的数为自由元,那个位置为自由位置
    那么我们考虑自由元放在什么位置
    ①如果放在自由位置,那么剩余的数成了(f[i - 1])
    ②如果不放在自由位置,有(i - 1)个位置,剩余(i - 1)的方案就是(g[i - 1])

    综上

    [f[i] = (i - 1) * g[i - 1] ]

    [g[i] = f[i - 1] + (i - 1) * g[i - 1] ]

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    #define LL long long int
    #define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
    #define REP(i,n) for (int i = 1; i <= (n); i++)
    #define BUG(s,n) for (int i = 1; i <= (n); i++) cout<<s[i]<<' '; puts("");
    using namespace std;
    const int maxn = 1000005,maxm = 100005,INF = 1000000000,P = 1000000007;
    inline int read(){
    	int out = 0,flag = 1; char c = getchar();
    	while (c < 48 || c > 57){if (c == '-') flag = -1; c = getchar();}
    	while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
    	return out * flag;
    }
    LL fac[maxn],inv[maxn],fv[maxn],f[maxn],g[maxn];
    int n,m,T;
    LL C(int x,int y){
    	return fac[x] * fv[y] % P * fv[x - y] % P;
    }
    int main(){
    	fac[0] = 1;
    	for (int i = 1; i <= 1000000; i++) fac[i] = fac[i - 1] * i % P;
    	inv[0] = inv[1] = 1;
    	for (int i = 2; i <= 1000000; i++) inv[i] = (P - P / i) * inv[P % i] % P;
    	fv[0] = 1;
    	for (int i = 1; i <= 1000000; i++) fv[i] = fv[i - 1] * inv[i] % P;
    	f[0] = 1; f[1] = 0; g[1] = 1; g[0] = 1;
    	for (int i = 2; i <= 1000000; i++){
    		f[i] = (i - 1) * g[i - 1] % P;
    		g[i] = (f[i - 1] + (i - 1) * g[i - 1] % P) % P;
    	}
    	T = read();
    	while (T--){
    		n = read(); m = read();
    		printf("%lld
    ",C(n,m) * f[n - m] % P);
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    CSS all 属性
    platform (Operating System) – Python 中文开发手册
    HTML DOM querySelectorAll() 方法
    Linux enable命令
    dnat & snat
    鲲鹏920 上实现lvs fullnat--安装ipvsadm
    kylin os操作系统镜像适配ironic 裸金属 管理
    neutron network:router_gateway
    tcpdump实现和run_filter
    ebpf sock sk_filter实现
  • 原文地址:https://www.cnblogs.com/Mychael/p/8865047.html
Copyright © 2011-2022 走看看