【组合+错排】BZOJ4517(Sdoi2016)[排列计数]题解

来源:互联网 发布:mac放大窗口的快捷键 编辑:程序博客网 时间:2024/05/19 13:16

题目概述

如果 ai=ii 是稳定的。给出 n,m ,求稳定数为 mn 的排列的个数。

解题报告

其实很简单……先选出 m 个稳定位置,然后另外 nm 强制不稳定。

强制不稳定也就是 aii ,即错排。


错排递推公式: D(0)=1,D(1)=0D(i)=(i1)[D(i2)+D(i1)]
推导:将 i 放在 k(ki) 上,有 i1 种方法。
然后若 ki 上,则剩下 i2 个数错排,方案数 D(i2)
否则就当 ki ,进行错排,方案数 D(i1)

示例程序

#include<cstdio>#include<cctype>using namespace std;typedef long long LL;const int maxn=1000000,MOD=1e9+7;int te,n,m,fac[maxn+5],INV[maxn+5],D[maxn+5];#define Eoln(x) ((x)==10||(x)==13||(x)==EOF)inline char readc(){    static char buf[100000],*l=buf,*r=buf;    if (l==r) r=(l=buf)+fread(buf,1,100000,stdin);    if (l==r) return EOF;return *l++;}inline int readi(int &x){    int tot=0,f=1;char ch=readc(),lst='+';    while (!isdigit(ch)) {if (ch==EOF) return EOF;lst=ch;ch=readc();}    if (lst=='-') f=-f;    while (isdigit(ch)) tot=(tot<<3)+(tot<<1)+ch-48,ch=readc();    return x=tot*f,Eoln(ch);}void Make(){    INV[0]=INV[1]=1;for (int i=2;i<=maxn;i++) INV[i]=MOD-(LL)(MOD/i)*INV[MOD%i]%MOD;    fac[0]=fac[1]=1;for (int i=2;i<=maxn;i++) fac[i]=(LL)fac[i-1]*i%MOD,INV[i]=(LL)INV[i-1]*INV[i]%MOD;    D[0]=1;D[1]=0;for (int i=2;i<=maxn;i++) D[i]=(LL)(i-1)*(D[i-1]+D[i-2])%MOD;}inline int C(int x,int y) {if (x<y) return 0;return (LL)fac[x]*INV[y]%MOD*INV[x-y]%MOD;}int main(){    freopen("program.in","r",stdin);    freopen("program.out","w",stdout);    for (Make(),readi(te);te;te--)    {        readi(n);readi(m);if (n<m) {puts("0");continue;}        printf("%lld\n",(LL)C(n,m)*D[n-m]%MOD);    }    return 0;}
原创粉丝点击