题意:有n个人与n个名字进行配对,求配对成功一半以上的正确种数
链接:http://acm.hdu.edu.cn/showproblem.php?pid=2068
思路:组合数+全错位排列,假设有n个人,配对成功i个,num表示全错位排列数量,即配对成功数量为C(i,n)+num[n-i];因此有n个人时,配对成功一半以上的种数有Σ(C(i,n)+num[n-i]),i=n/2....n
注意点:求组合数时注意溢出
以下为AC代码:
Run ID | Submit Time | Judge Status | Pro.ID | Exe.Time | Exe.Memory | Code Len. | Language | Author |
12680842 | 2015-01-11 12:54:00 | Accepted | 2068 | 15MS | 1204K | 1848 B | G++ | luminous11 |
#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <vector>
#include <deque>
#include <list>
#include <cctype>
#include <algorithm>
#include <climits>
#include <queue>
#include <stack>
#include <cmath>
#include <map>
#include <set>
#include <iomanip>
#include <cstdlib>
#include <ctime>
#define ll long long
#define ull unsigned long long
#define all(x) (x).begin(), (x).end()
#define clr(a, v) memset( a , v , sizeof(a) )
#define pb push_back
#define mp make_pair
#define read(f) freopen(f, "r", stdin)
#define write(f) freopen(f, "w", stdout)
using namespace std;
const double pi = acos(-1);
inline ll calc ( ll n, int k )
{
ll tmp = 1;
ll div = 1;
for ( ll i = 1; i <= k; i ++ ) {
tmp *= n;
div *= i;
if ( tmp % div == 0 ){
tmp /= div;
div = 1;
}
n --;
}
return tmp / div;
}
inline int fun ( int i )
{
if ( i & 1 ) {
return -1;
} else {
return 1;
}
}
int main()
{
ios::sync_with_stdio( false );
int num[30] = { 0, 0 };
for ( int i = 2; i < 30; i ++ ) {
num[i] = num[i-1] * i + fun ( i );
}
num[0] = 1;
ll ans[30] = { 0, 1, 1 };
for ( int i = 3; i < 30; i ++ ) {
if ( i & 1 ) {
for ( int j = i / 2 + 1; j <= i; j ++ ) {
// cout << calc ( i, j ) * num[i-j] << endl;
ans[i] += calc ( i, j ) * num[i-j];
}
}
else {
for ( int j = i / 2; j <= i ; j ++ ) {
ans[i] += calc ( i, j ) * num[i-j];
// cout << calc ( i, j ) * num[i-j] << endl;
}
}
}
int n;
while ( cin >> n && n ) {
cout << ans[n] << endl;
}
return 0;
}