bzoj4517排列计数 错排+组合

4517: [Sdoi2016]排列计数

Time Limit: 60 Sec  Memory Limit: 128 MB
Submit: 1491  Solved: 903
[Submit][Status][Discuss]

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

很显然发现只要有n-m个元素错排,其余元素在原位置就可以贡献答案

任意选m个元素为稳定,其余元素完全错排  ans=f[n-m]*c[n][m]     f[]为错排方案  c[][]为组合数

组合数无法递推求,我们用公式n!/((n-m)!*m!),但注意下面的取逆元  又由于mod是一个素数,根据费马小定理,a^(p-2)=1(mod p) p为素数

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
#define inf 0x3f3f3f3f
#define ll long long
#define N 1000005
#define mod 1000000007
using namespace std;
ll f[N],fac[N];

ll qp(ll a,int b){
    ll c=1;
    while(b){
        if(b&1)c=(c*a)%mod;
        a=(a*a)%mod;
        b>>=1;
    }
    return c;
}

int main(){
#ifdef wsy
    freopen("data.in","r",stdin);
#else
    //freopen(".in","r",stdin);
    //freopen(".out","w",stdout);
#endif
    int T;
    scanf("%d",&T);
    f[1]=0;f[2]=1;f[0]=1;
    for(register int i=3;i<=1e6;i++)
    f[i]=(i-1)*(f[i-1]+f[i-2])%mod;
    fac[0]=fac[1]=1;
    for(register int i=2;i<=1e6;i++)
    fac[i]=(fac[i-1]*i)%mod;
    while(T--){
        int n,m;
        scanf("%d%d",&n,&m);
        ll t1=qp(fac[m],mod-2),t2=qp(fac[n-m],mod-2);
        ll c=(fac[n]*t1)%mod;
        c=(c*t2)%mod;
        ll res=(f[n-m]*c)%mod;
        cout<<res<<endl;
    }
    return 0;
}
时间: 2024-10-09 04:02:45

bzoj4517排列计数 错排+组合的相关文章

BZOJ 4517: [Sdoi2016]排列计数 错排+逆元

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 行,每行一个数,表示

【转】HDU-2049-不容易系列之(4)——考新郎:错排+组合

现对于上一道”神.上帝以及老天爷” 只求M个数的错排数 不同的本题 是求N个数中M的错排数 先从N个数中 取M个数有CnM种取法 再乘上M的错排数就是答案 错排数的求法参考上一篇文章 其中组合公式如下 #include<iostream> #include<string> #include<iomanip> using namespace std; int main() { long long a[21]={0, 0, 1}; // a[i]表示i个数的错排种类 lon

HDU1465 第六周L题(错排组合数)

L - 计数,排列 Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Description 大家常常感慨,要做好一件事情真的不容易,确实,失败比成功容易多了!  做好“一件”事情尚且不易,若想永远成功而总从不失败,那更是难上加难了,就像花钱总是比挣钱容易的道理一样.  话虽这样说,我还是要告诉大家,要想失败到一定程度也是不容易的.比如,我高中的时候,就有一个神奇的女生,在英语考试的时候,竟然

HDU 2068 RPG的错排

要求答对一半或以上就算过关,请问有多少组答案能使他顺利过关. 逆向思维,求答错一半或以下的组数 1,错排 错排公式的由来 pala提出的问题: 十本不同的书放在书架上.现重新摆放,使每本书都不在原来放的位置.有几种摆法? 这个问题推广一下,就是错排问题: n个有序的元素应有n!种不同的排列.如若一个排列式的所有的元素都不在原来的位置上,则称这个排列为错排.递推的方法推导错排公式 当n个编号元素放在n个编号位置,元素编号与位置编号各不对应的方法数用M(n)表示,那么M(n-1)就表示n-1个编号元

浅析错排问题

定义:n个有序的元素应有n!种不同的排列.如果一个排列使得所有的元素都不在原来的位置上,则称这个排列为错排.任给一个n,求出1,2,3,...,n的错排个数D为多少,并且给出所有的错排方案 推理: 第一步,把第n个元素放在一个位置,比如位置k,一共有n-1种方法: 第二步,放编号为k的元素,这时有两种情况:⑴把它放到位置n,那么,对于剩下的n-1个元素,由于第k个元素放到了位置n,剩下n-2个元素就有D(n-2)种方法:⑵第k个元素不把它放到位置n,这时,对于这n-1个元素,有D(n-1)种方法

hdu 1465 不容易系列之一(错排模板)

不容易系列之一 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 20941    Accepted Submission(s): 8937 Problem Description 大家常常感慨,要做好一件事情真的不容易,确实,失败比成功容易多了!做好"一件"事情尚且不易,若想永远成功而总从不失败,那更是难上加难了,就像花钱总是比

递推之错排公式

错排问题 就是一种递推式,不过它比较著名且常用,所以要熟记! 方法一: n各有序的元素应有n!种不同的排列.如若一个排列式的所有的元素都不在原来的位置上,则称这个排列为错排.任给一个n,求出1,2,……,n的错排个数Dn共有多少个.递归关系式为:D(n)=(n-1)(D(n-1)+D(n-2))D(1)=0,D(2)=1可以得到:错排公式为 f(n) = n![1-1/1!+1/2!-1/3!+……+(-1)^n*1/n!] 其中,n!=1*2*3*.....*n,特别地,有0!=0,1!=1.

【BZOJ4517】[Sdoi2016]排列计数 组合数+错排

[BZOJ4517][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 行,每行一个

计数,排列错排公式

计数,排列Crawling in process... Crawling failed Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Submit Status Description Input Output Sample Input Sample Output Hint Description 大家常常感慨,要做好一件事情真的不容易,确实,失败比成功容易多了! 做好“一件”事情尚且不易