hdu2068 错排公式

一个有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;
	}
}

猜你喜欢

转载自blog.csdn.net/hanker99/article/details/84197481
今日推荐