您的位置:首页 > 其它

bzoj4517: [Sdoi2016]排列计数

2018-04-03 22:01 501 查看

题目链接

bzoj4517: [Sdoi2016]排列计数

题解

组合数问题:

\(ans = C(n,m) * D(n-m)\) , \(D(x)\)表示元素为x个的序列的错排数

对于\(D(x)\) 上错排数递推公式

\(D(x) = (x-1)* (D(x-1) + D(x-2))\)

考场上对与D(x) 打的容斥 真是naive

代码

// T2
// ans = C_n^m * (A(n,n) - A(n,n-m-1) + A(n,n-m-2).....)
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
inline int read() {
int x = 0,f = 1;
char c = getchar ();
while(c < '0' || c > '9') { if(c == '-') f = -1;c = getchar();}
while(c <= '9' && c >= '0') x = x * 10 + c - '0' ,c = getchar();
return x * f;
}
const long long mod = 1e9 + 7;
const int maxn = 1000007;
#define LL long long
LL jc[maxn],f[maxn];
inline LL poow(LL a,int k = mod-2) {
LL ret = a;
for(k --;k;k >>= 1,a = a * a % mod)
if(k & 1) ret = ret * a % mod;
return ret;
}
inline LL inv(LL x) { return poow(x); }

LL C (int n,int m) {
return (jc
* inv(jc[m] * jc[n - m] % mod)  ) % mod;
}
/* LL get_num(int n) {
//  if(n == 1) return 1;
LL ret = 0;
for(int k,i = 2;i <= n;++ i) {
if(i&1) k = -1;else k = 1;
ret = ( ret +  (k * (jc
*(inv(jc[i]) % mod) )%mod ) +mod ) %mod;
}
return ret;
} */
int main() {
//freopen("permutation.in","r",stdin); freopen("permutation.out","w",stdout);
int T = read();
jc[0]=1;
for(int i = 1;i <= 1000003;++ i)
jc[i] = jc[i-1] * i % mod;
//for(int i = 1;i <= 500003;++ i)
f[1]=f[0]=1;
for(int i = 1;i <= 1000003;++ i) f[i] = (i - 1) *( f[i-1] + f[i-2])%mod;
for( int n,m; T --;) {
n = read(),m = read();
LL Cnm = C(n,m);
if(n == m) {puts("1");continue; }
//  printf("%lld\n",get_num(n-m));
printf("%lld\n",(Cnm * f[n - m] )%mod );
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: