链接:
https://www.nowcoder.com/acm/contest/116/F
来源:牛客网
来源:牛客网
猴子排序的期望
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld
题目描述
我们知道有一种神奇的排序方法叫做猴子排序,就是把待排序的数字写在卡片上,然后让猴子把卡片扔在空中,等落下的时候观察这些卡片是否从左到右已经排序完成(我们认为不会发生卡片落地后叠在一起的情况)如果有序则排序完成,否则让猴子再扔一遍,直到卡片有序,那么问题来了,给你N个卡片,每个卡片上写着一个大写字母,请问猴子第一次扔这些卡片就按字典序排序完成的概率有多大?
输入描述:
第一行是一个整数N(1<N<100)表示给猴子N张卡片,接下来是一个长度为N的字符串,代表这些卡片上所写的字母。
输出描述:
输出一行,表示猴子排序第一次就成功的概率(用分子为1的分数表示)。
示例1
输入
7
SCIENCE
SCIENCE
输出
1/1260
解题思路:用高精度的乘法先把分子,分母求出来,然后再用高精度的除法把分子化为1即可。所以说,这题你只需要一个高精度的板子就可以了:
大数的四则运算
AC代码:
#include<stdio.h> #include<iostream> #include<algorithm> #include<string.h> #include<math.h> #include<stdlib.h> #include<queue> #include<map> #define bug printf("--------"); using namespace std; typedef long long LL; const int INF = 1e9; const int MAXSIZE = 200; int n, a[100]; char str[200], fm[200], s2[5], s3[200], fz[200]; void Mul(char *str1, char *str2, char *str3); void Div(char *str1, char *str2, char *str3); //str3 = str1*str2; //str3 = str1/str2; int main() { while(~scanf("%d", &n)) { scanf("%s", str); fz[0] = '1'; fm[0] = '1'; fm[1] = '\0'; fz[1] = '\0'; memset(a, 0, sizeof(a)); for(int i = 0; i < n; i ++) { a[str[i]] ++; } for(int i = 1; i < 100; i ++) { for(int j = a[i]; j >= 1; j --) { sprintf(s2, "%d", j); memset(s3, '0', sizeof(s3)); Mul(fz, s2, s3); strcpy(fz, s3); //不断更新 } } for(int i = 2; i <= n; i ++) { sprintf(s2, "%d", i); memset(s3, '0', sizeof(s3)); Mul(fm, s2, s3); strcpy(fm, s3); //不断更新 } memset(s3, '0', sizeof(s3)); Div(fm, fz, s3); printf("1/%s\n", s3); } return 0; } void Mul(char *str1, char *str2, char *str3) { int i, j = 0, i1, i2, tmp, carry, jj; int len1 = (int)strlen(str1), len2 = (int)strlen(str2); char ch; jj = carry = 0; for (i1 = len1 - 1; i1 >= 0; --i1) { j = jj; for (i2 = len2 - 1; i2 >= 0; --i2, ++j) { tmp = (str3[j] - '0') + (str1[i1] - '0') * (str2[i2] - '0') + carry; if (tmp > 9) { carry = tmp / 10; str3[j] = tmp % 10 + '0'; } else { str3[j] = tmp + '0'; carry = 0; } } if (carry) { str3[j] = carry + '0'; carry = 0; j++; } jj++; } j--; while (str3[j] == '0' && j > 0) { j--; } str3[++j] = '\0'; for (i = 0, --j; i < j; ++i, --j) { ch = str3[i]; str3[i] = str3[j]; str3[j] = ch; } return ; } void Div(char *str1, char *str2, char *str3) { int i1, i2, i, j, jj = 0, tag, carry, cf, c[MAXSIZE]; int len1 = (int)strlen(str1), len2 = (int)strlen(str2), lend; char d[MAXSIZE]; memset(c, 0, sizeof(c)); memcpy(d, str1, len2); lend = len2; j = 0; for (i1 = len2 - 1; i1 < len1; ++i1) { if (lend < len2) { d[lend] = str1[i1+1]; c[j] = 0; ++j; ++lend; } else if (lend == len2) { jj = 1; for (i = 0; i < lend; ++i) { if (d[i] > str2[i]) { break; } else if (d[i] < str2[i]) { jj = 0; break; } } if (jj == 0) { d[lend] = str1[i1+1]; c[j] = 0; ++j; ++lend; continue; } } if (jj == 1 || lend > len2) { cf = jj = 0; while (d[jj] <= '0' && jj < lend) { ++jj; } if (lend - jj > len2) { cf = 1; } else if (lend - jj < len2) { cf = 0; } else { i2 = 0; cf = 1; for (i = jj; i < lend; ++i) { if (d[i] < str2[i2]) { cf = 0; break; } else if (d[i] > str2[i2]) { break; } ++i2; } } while (cf) { i2 = len2 - 1; cf = 0; for (i = lend - 1; i >= lend - len2; --i) { d[i] = d[i] - str2[i2] + '0'; if (d[i] < '0') { d[i] = d[i] + 10; carry = 1; --d[i - 1]; } else { carry = 0; } --i2; } ++c[j]; jj = 0; while (d[jj] <= '0' && jj < lend) { ++jj; } if (lend - jj > len2) { cf = 1; } else if (lend - jj < len2) { cf = 0; } else { i2 = 0; cf = 1; for (i = jj; i < lend; ++i) { if (d[i] < str2[i2]) { cf = 0; break; } else if (d[i] > str2[i2]) { break; } ++i2; } } } jj = 0; while (d[jj] <= '0' && jj < lend) { ++jj; } for (i = 0; i < lend - jj; ++i) { d[i] = d[i + jj]; } d[i] = str1[i1 + 1]; lend = i + 1; j++; } } i = tag = 0; while (c[i] == 0) { ++i; } for (; i < j; ++i, ++tag) { str3[tag] = c[i]+'0'; } str3[tag] = '\0'; return ; }