1. 程式人生 > >【組合+錯排】BZOJ4517(Sdoi2016)[排列計數]題解

【組合+錯排】BZOJ4517(Sdoi2016)[排列計數]題解

題目概述

如果 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; }