一个有n个元素的排列,若一个排列中所有的元素都不在自己原来的位置上,那么这样的排列就称为原排列的一个错排,n个元素的错排数记为D(n)。那么对于这样的排列D(n)有多少种呢?我们一步一步进行分析:
首先,对于D(n),有1~n这样n个元素错排,所以对于第一个元素①,它现在可能的位置有(n-1)个,倘若它在第k个元素的位置上,对于第k个元素而言,它所在的位置就有两种可能:第一种,它处在非第一个元素①位置上,所以对于接下来的排列就相当于是n-1个元素的错排,即D(n-1);第二种,它处在第一个元素①的位置上,所以在排列D(n)中有两个元素找到了位置,那么接下来的队列就相当于是n-2个元素的错排。因此,对于D(n)都有D(n)=(n-1)*(D(n-1)+D(n-2)) 特殊的,D(1)=0,D(2)=1。
Problem Description
今年暑假杭电ACM集训队第一次组成女生队,其中有一队叫RPG,但竟然不知道RPG的n个人具体是谁谁。RPG给他机会让他猜猜,......女生们只要求他答对一半或以上就算过关,请问有多少组答案能使他顺利过关。
Input
输入的数据里有多个case,每个case包括一个n,代表有几个女生,(n<=25), n = 0输入结束。
Sample Input
1 2 0
Sample Output
1 1
#include "pch.h"
#pragma warning (disable:4996)
#include<stdio.h>
#include <iostream>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
long long comb[100][100];
long long wcomb[100];
long long com(int a, int b) {
if (comb[a][b] >= 0) return comb[a][b];
long long res;
if (a == b || b == 0) return res = 1;
else res = com(a - 1, b) + com(a - 1, b - 1);
return comb[a][b] = res;
}
long long wcom(int b) {
if (b == 1) return wcomb[1] = 0;
if (b == 2) return wcomb[2] = 1;
long long res;
wcomb[b] = (b - 1)*(wcom(b - 1) + wcom(b - 2));
return wcomb[b];
}
int main()
{
//freopen("datain.txt", "r", stdin);
int a;
while (~scanf("%d", &a)) {
if (!a) break;
memset(comb, -1, sizeof(comb));
memset(wcomb, -1, sizeof(wcomb));
long long sum = 1;//全部正确的情况:1
//要求至少猜对一半或以上,则允许错排的个数为a/2
//小数部分抹去
//当女生有3个的时候,a/2=1,但是一个女生无法错排
//错排的最小数字应该是2
for (int b = a / 2;b >= 2;b--) {
//当然此处写成b>=1也没关系,因为wcom(1)==0;
sum += com(a, b)*wcom(b);
}
cout << sum << endl;
}
}