[玲珑学院OJ 1029 - Bob and Alice are playing factors]Miller_Rabin+Pollard_rho+排列组合+逆元
题目链接:[玲珑学院OJ 1029 - Bob and Alice are playing factors]
题意描述:给定
A1
找一个最长的序列
A1,A2,…,Ak
,序列
A
满足
解题思路:首先对
A1
进行质因子分解,由于
A1
数字太大,可以用Miller_Rabin+Pollard_rho搞。最长序列的长度很简单,就是质因子的个数总和+1。最长序列的个数,就要用到排列组合的知识了。最长序列的个数=质因子个数总和的全排列除以每个质因子的个数的全排列。除法用逆元搞一搞就OK了。高中的知识,但是,忘记怎么证明去了。有时间一定要好好复习一下排列组合了……还有,,这个题目,,WA得不忍直视….
#include <map>
#include <ctime>
#include <queue>
#include <cmath>
#include <cstdio>
#include <string>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define FIN freopen("input.txt","r",stdin)
typedef long long LL;
const LL MOD = 1e9 + 7;
const LL MAXN = 100 + 5;
const int S = 20;
LL T, N;
LL fact[MAXN];
LL tol;
LL A(LL x) {
LL ret = 1;
for (LL i = 1; i <= x; i++) {
ret = ret * i % MOD;
}
return ret;
}
LL mult_mod(LL a, LL b, LL c) {
a %= c;
b %= c;
LL ret = 0;
while(b) {
if(b & 1) {
ret += a;
ret %= c;
}
a <<= 1;
if(a >= c)a %= c;
b >>= 1;
}
return ret;
}
LL quick_pow(LL x, LL n, LL mod) {
if(n == 1)return x % mod;
x %= mod;
LL tmp = x;
LL ret = 1;
while(n) {
if(n & 1) ret = mult_mod(ret, tmp, mod);
tmp = mult_mod(tmp, tmp, mod);
n >>= 1;
}
return ret;
}
bool check(LL a, LL n, LL x, LL t) {
LL ret = quick_pow(a, x, n);
LL last = ret;
for(int i = 1; i <= t; i++) {
ret = mult_mod(ret, ret, n);
if(ret == 1 && last != 1 && last != n - 1) return true;
last = ret;
}
if(ret != 1) return true;
return false;
}
bool Miller_Rabin(LL n) {
if(n < 2)return false;
if(n == 2)return true;
if((n & 1) == 0) return false;
LL x = n - 1;
LL t = 0;
while((x & 1) == 0) {
x >>= 1;
t++;
}
for(int i = 0; i < S; i++) {
LL a = rand() % (n - 1) + 1;
if(check(a, n, x, t))
return false;
}
return true;
}
LL gcd(LL a, LL b) {
if(a == 0)return 1;
if(a < 0) return gcd(-a, b);
while(b) {
LL t = a % b;
a = b;
b = t;
}
return a;
}
LL Pollard_rho(LL x, LL c) {
LL i = 1, k = 2;
LL x0 = rand() % x;
LL y = x0;
while(1) {
i++;
x0 = (mult_mod(x0, x0, x) + c) % x;
LL d = gcd(y - x0, x);
if(d != 1 && d != x) return d;
if(y == x0) return x;
if(i == k) {
y = x0;
k += k;
}
}
}
void findfac(LL n) {
if(Miller_Rabin(n)) {
fact[tol++] = n;
return;
}
LL p = n;
while(p >= n) p = Pollard_rho(p, rand() % (n - 1) + 1);
findfac(p);
findfac(n / p);
}
LL inv(LL a, LL mod) {
return quick_pow(a, mod - 2, mod);
}
int main() {
#ifndef ONLINE_JUDGE
FIN;
// FOUT;
#endif // ONLINE_JUDGE
LL cas = 0, ans1, ans2;
scanf("%lld", &T);
while(T --) {
scanf("%lld", &N);
if(N == 1) {
printf("Case #%lld: 1 1\n", ++cas);
continue;
}
if(Miller_Rabin(N)) {
printf("Case #%lld: 2 1\n", ++cas);
continue;
}
tol = 0;
findfac(N);
ans1 = (1 + tol) % MOD;
ans2 = A(tol);
map<LL, LL> fuck;
for (LL i = 0; i < tol; i++) fuck[fact[i]] ++;
for (map<LL, LL>::iterator iter = fuck.begin(); iter != fuck.end(); iter ++) {
ans2 = ans2 * inv(A(iter->second), MOD) % MOD;
}
printf("Case #%lld: %lld %lld\n", ++cas, ans1, ans2);
}
return 0;
}