BZOJ4517P4071 [SDOI2016]排列計數
阿新 • • 發佈:2018-12-11
錯排+組合數
不難發現把穩定的m個數除掉後,就是一個錯排問題,錯排的遞推式是D[i]=(i-1)*(d[i-1]+d[i-2])具體證明自己去翻一翻別的部落格,我後續也會寫 但是這m個位置是不固定的,所以我們可以在n個位置裡任意選m個也就是,然後在剩下的n-m個位置裡做錯排也就是,然後根據乘法原理總的方案數就是,然後因為涉及到取模,所以要求一個逆元,1e9+7是個大質數,所以直接就行了
程式碼
//By AcerMo
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define lli long long int
using namespace std;
const int M=1000500;
const int mod=1e9+7;
lli n,m;
lli C[M],D[M],N[M];
inline lli read()
{
lli x=0;char ch=getchar();
while (ch>'9'||ch<'0') ch=getchar ();
while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
return x;
}
inline void write(int x)
{
if (x>9) write(x/10);
putchar(x%10+'0');
return ;
}
inline lli fpow(lli a,lli b)
{
lli ans=1;
for (;b;a=(a*a)%mod,b>>=1)
if (b&1) ans=(ans*a)%mod;
return ans;
}
inline void fir()
{
C[0]=1;
for (int i=1;i<M;i++)
{
C[i]=(C[i-1]*i)%mod;
N[i]=fpow(C[i],mod-2);
}
D[1]=0;D[2]=1;D[3]=2;
for (int i=4;i<M;i++)
D[i]=(i-1)*(D[i-1]+D[i-2])%mod;
return ;
}
signed main()
{
int t=read();fir();
while (t--)
{
n=read();m=read();
if (n-m==1){puts("0");continue;}
if (m==n) {puts("1");continue;}
if (m==0) {write(D[n]);puts("");continue;}
lli ans=(C[n]*N[m])%mod;
lli que=(N[n-m]*D[n-m])%mod;
write((ans*que)%mod);puts("");
}
return 0;
}