|
题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=2984
/**//* 题意: 给出一个长度为N(N <= 1000000)的串,要求求出所有串的不重复排列的方案。 输出方案数的最后一个非零位。
题解: 组合数学 + 数论
思路: 首先将所有字符归类,相同的放在一起计数,然后就是一个组合问题了,可以 想象成L个抽屉,然后一类一类插入,比如有A1个'a',那么就是C(L, A1)种方案, 还有L-A1个位置,继续下一步,如果有A2个'b'那么下一趟就是C(L-A1, A2)。将所 有的组合数相乘就是答案了。 但是这题要求求的是答案的最后一个非零位,于是问题需要转化一下,每次不 能直接将C(n, m)求出来,可以这样想,导致一个数末几尾有0的条件是这个数中有 至少一对2和5,C(n, m) = n! / m! / (n-m)!,用F[x]来记录x的阶乘中 2和5的个 数以及其它数的乘积,那么就可以把C(n, m)中其它数的乘积求出来: ans = X[n] * X[m] * Inv[ X[n-m] ]; 其中X[v] 表示v的阶乘中其它数的乘积,Inv[v]表示v对于10的逆。 所有的组合数求完之后,将剩下的2和5匹配掉,多余部分再乘到答案上即可。 */
#include <iostream> #include <cstring> #include <cstdio>
using namespace std;
int hash[26]; char str[1000001];
int exp(int a, int b, int& x, int& y) { int q; if(b == 0) { q = a; x = 1; y = 0; return q; } q = exp(b, a%b, x, y); int tmp = x; x = y; y = tmp - a/b * y; return q; }
int inv(int v, int m) { int x, y; exp(v, m, x, y); return (x % m + m) % m; }
struct Triple { int num2, num5, other_product; Triple() { num2 = num5 = 0; other_product = 1; } Triple(int _2, int _5, int _p) { num2 = _2; num5 = _5; other_product = _p; } }; Triple tp[1000010];
Triple Go(int n) { return tp[n]; }
int AccPro = 1;
Triple C(int n, int m) { Triple U, D[2]; U = Go(n); D[0] = Go(m); D[1] = Go(n - m);
U.num2 -= D[0].num2 + D[1].num2; U.num5 -= D[0].num5 + D[1].num5;
AccPro = AccPro * D[0].other_product * D[1].other_product % 10; return U; }
int Binary(int a, int b, int c) { if(!b) return 1 % c; int tmp = Binary(a*a%c, b/2, c); if(b & 1) tmp = tmp * a % c; return tmp; }
int main() { int i; for(i = 2; i < 1000001; i++) { tp[i] = tp[i-1];
int val = i; while(val % 2 == 0) { val /= 2; tp[i].num2 ++; } while(val % 5 == 0) { val /= 5; tp[i].num5 ++; } tp[i].other_product *= val; tp[i].other_product %= 10; }
while(scanf("%s", str) != EOF) { memset(hash, 0, sizeof(hash)); int len = strlen(str); for(i = 0; i < len; i++) { hash[ str[i] - 'a' ] ++; } Triple ans; AccPro = 1; for(i = 0; i < 26; i++) { if(hash[i]) { Triple X = C(len , hash[i]); ans.num2 += X.num2; ans.num5 += X.num5; ans.other_product = ans.other_product * X.other_product % 10;
len -= hash[i]; } } AccPro = inv(AccPro, 10);
int as = 1;
if(ans.num2 < ans.num5) { ans.num5 -= ans.num2; as = ans.other_product * Binary(5, ans.num5, 10) * AccPro % 10; }else { ans.num2 -= ans.num5; as = ans.other_product * Binary(2, ans.num2, 10) * AccPro % 10; }
printf("%d\n", as); } return 0; }
|