Hdu 1133 Buy the ticket <卡特兰数+大数处理>
题意:
有m个人拿50 n个人拿100 前台没零钱..问多少种合法的排队方法
思路:
网上摘录:
假设m=4,n=3,的一个序列是:0110100显然,它不合法
然后我们把他稍微变化一下:把第一个不合法的“1”后面的所有数0位为1, 1位为0;这样我们得到了另一个序列:0111011,说明每个不合法的都有一个这样的序列跟他一一对应
所以计算公式就是:合法的排列方式=所有排列方式-非法排列方式
这里非法排列方式的计算 就是:(- )*M!*N!
然而在这题,因为每个人都是不同的,所以还要乘以 M!*N!
所以得出最终方程:
F(N)=(-)*M!*N! ;
然后再化简一下;
F(N)=(M+N)! * (M-N+1)/(M+1)
Tips:
注意有n>m的情况..
还有各种大数的处理..
Code:
View Code
1 #include <stdio.h> 2 #include <cstring> 3 using namespace std; 4 #define MAX 100 ///大数的位数 5 #define Base 10000 6 7 void multiply(int *a, int b) ///大数a*小数b 8 { 9 int i, tmp = 0; 10 for(i = MAX - 1; i >= 0; --i){ 11 tmp += b*a[i]; 12 a[i] = tmp%Base; 13 tmp /= Base; 14 } 15 } 16 17 void divide(int *a, int b)///大数a除小数b 18 { 19 int i, div = 0; 20 for(i = 0; i < MAX; ++i){ 21 div = div*Base + a[i]; 22 a[i] = div/b; 23 div %= b; 24 } 25 } 26 27 int f[210][MAX]; 28 void setFact()///大数阶乘<200> 29 { 30 f[0][MAX-1] = f[1][MAX-1] = 1; 31 for(int i = 2; i <= 200; ++i){ 32 memcpy(f[i], f[i-1], MAX*sizeof(int)); 33 multiply(f[i], i); 34 } 35 } 36 37 void outPut(int *ans) 38 { 39 int i = 0; 40 while(i < MAX && ans[i] == 0) 41 i++; 42 printf("%d", ans[i++]); 43 while(i < MAX) 44 printf("%04d", ans[i++]); 45 puts(""); 46 } 47 48 49 int main() 50 { 51 int i, j, k; 52 int m, n; 53 int T = 1; 54 int ans[MAX]; 55 setFact(); 56 while(scanf("%d %d", &m, &n), m+n) 57 { 58 printf("%Test #%d:\n", T++); 59 if(n > m){ 60 printf("0\n"); 61 continue; 62 } 63 memcpy(ans, f[m+n], MAX*sizeof(int)); /// ( m + n )! 64 multiply(ans, m-n+1); ///(m+n)! * (m-n+1) 65 divide(ans, m+1); ///(m+n)! * (m-n+1)/(m+1) 66 outPut(ans); 67 } 68 return 0; 69 }