您的位置:首页 > 其它

LightOJ-1095 Arrange the Numbers

2017-01-03 20:37 417 查看

题目分析

这道题我的第一个想法是利用容斥原理,很明显首先得到Ckm表示选取K个位置做好人,然后对于剩余的部分,我们不能让前面的m-k个人坐上他们原来的位置,因此直接可以用总共排列的方法数,减去一个人m-k个人中有一个坐在原来位置上的,加上2个人坐在原来位置上的,减去2个人坐在原来位置上的。。。。公式是:

Ckm∗∑i=1m−kCim−k∗f[n−k−i]∗−1n

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define LL long long
const int maxn = 1010;
const int mod = 1e9+7;

LL C[maxn][maxn], f[maxn];

void init(){
for(int i = 0; i < maxn; i++){
C[i][0] = C[i][i] = 1LL;
for(int j = 1; j < i; j++) C[i][j] = (C[i-1][j] + C[i-1][j-1])%mod;
}
f[0] = 1LL;
for(int i = 1; i < maxn; i++) f[i] = f[i-1]*i%mod;
}

int main(){
init();
int T, n, m, k;
scanf("%d", &T);
for(int kase = 1; kase <= T; kase++){
scanf("%d%d%d", &n, &m, &k);
LL ans = f[n-k];
for(int i = 1; i <= m-k; i++){
if(i&1) ans = (ans - C[m-k][i]*f[n-k-i]%mod)%mod;
else ans = (ans + C[m-k][i]*f[n-k-i]%mod)%mod;
}
if(ans < 0) ans += mod;
ans = (ans*C[m][k])%mod;
printf("Case %d: %lld\n", kase, ans);
}
return 0;
}


第二种写法是利用错排公式。

d[1]=0,d[2]=1,d[i]=(i−1)∗(d[i−1]+d[i−2])(n>2)

对于剩余的n-m个位置我们每次可选取i个放在原位置,剩余的利用错排公式计算得到的结果累加即可。

Ckm∗∑i=0n−mCin−m∗d[n−k−i]

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define LL long long
const int mod = 1e9+7;
const int maxn = 1e3+100;
LL C[maxn][maxn], D[maxn];

void init(){
for(int i = 0; i < maxn; i++){
C[i][0] = C[i][i] = 1;
for(int j = 1; j < i; j++)
C[i][j] = (C[i-1][j] + C[i-1][j-1])%mod;
}
D[0] = D[2] = 1;
D[1] = 0;
for(int i = 3; i < maxn; i++) D[i] = (LL)(i-1)*(D[i-2]+D[i-1])%mod;
}

int main(){
init();
int T, n, m, k;
scanf("%d", &T);
for(int kase = 1; kase <= T; kase++){
scanf("%d%d%d", &n, &m, &k);
LL ans = 0;
for(int i = 0; i <= n-m; i++){
ans = (ans + C[n-m][i]*D[n-k-i])%mod;
}
ans = ans*C[m][k]%mod;
printf("Case %d: %lld\n", kase, ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: