完全错排问题
题目链接:http://acm.nyist.net/JudgeOnline/problem.php?pid=451
就是求C(n, n-m)*s(m)的值啦,C(n, n-m)表示从n个人中任取n-m个人的组合数,s(m)表示m对人和纸条的完全错排种数;
组合数求法很简单就不细说了,推一下完全错排计算公式好了;
假设现在有编号1~m的m个求和编号1~m的m个盒子,将m个求均分到m个盒子中,且1号球不能放1号盒子,2号球不能放2号盒子。。。(m个球完全错排);
用s(m)表示m个球的完全错排方法数;
假设先放1号球,可以放编号2~m的盒子,有m-1种放法(先放任意编号的球都是一样的),假设后面m-1个球有a中放法,则s(m)=(m-1)*a;
假设1号球放在2号盒子里,接下来我们考虑:
(1):假设2号球放在1号盒子里,剩余的球有s(m-2)种放法;
(2):假设2号球不放1号盒子里,这时我们可以将1号盒子和2号盒子换下位子,(因为2号球不放1号盒子,所以我们可以把1号盒子当做2号盒子来看,这点比较难理解但很关键),
于是我们可以得到剩余的球有s(m-1)种放法;
所以a=s(m-1)+s(m-2);
即:s(m)=(m-1)*(s(m-1)*s(m-2);
代码:
1 #include <bits/stdc++.h> 2 #define MAXN 20+10 3 #define ll long long 4 using namespace std; 5 6 ll cc(ll n, ll m){ 7 ll ans=1; 8 for(ll i=n, k=1; k<=m; k++, i--){ 9 ans*=i; 10 } 11 for(int i=1; i<=m; i++){ 12 ans/=i; 13 } 14 return ans; 15 } 16 17 int main(void){ 18 ll n, m, a[MAXN]; 19 a[2]=1, a[3]=2; 20 for(int i=4; i<MAXN; i++){ 21 a[i]=(i-1)*(a[i-1]+a[i-2]); 22 } 23 while(scanf("%lld%lld", &n, &m)!=EOF){ 24 ll ans=cc(n, n-m)*a[m]; 25 cout << ans << endl; 26 } 27 return 0; 28 }
我就是我,颜色不一样的烟火 --- geloutingyu