ICPC2019 Xuzhou E. Multiply Pollard_Rho 大数分解
ICPC2019 Xuzhou E. Multiply Pollard_Rho 大数分解
题意
给出\(n\)个数\(a_i\),令\(Z = \prod a_i!\)
给出\(X,Y\),令\(b_i = Z \times X^i\) ,它想要一个最大的\(i\),使得\(b_i | Y!\)
\[N \leq 10^5\\
X,Y \leq10^{18}\\
a_i \leq 10^{18}
\]
分析
考虑到\(X\)的值没有阶乘,相对较小,应该从他来做文章
对要求的式子做变换,得到\(X^i | \frac{Y!}{Z}\)
由于\(X^i\),\(X\)的质因子不会受到\(i\)的影响,因此它的质因子不会很大
考虑使用\(Pollard\_Rho\)算法来分解\(X\),期望复杂度\(O(X^{\frac{1}{4}})\)
这样只要对每个质因子贪心地拼凑出来满足小于等于\(\frac{Y!}{Z}\)的即可,后者对应的质因子的指数可以通过简单的trick来完成
考虑一个阶乘\(n!\)的质因子\(d\)的出现次数
\[n! = (d \times 2d \times 3d...\lfloor\frac{n}{d}\rfloor d)\times a\\
= d^{\lfloor\frac{n}{d}\rfloor} \times \lfloor\frac{n}{d}\rfloor! \times a\\
= ...
\]
于是可以用一个while循环来搞定
此处直接使用kuangbin的模板
代码
#include<bits/stdc++.h>
#define pii pair<int,int>
#define fi first
#define se second
#define re register
using namespace std;
typedef long long ll;
ll rd(){
ll x = 0;
char ch = getchar();
while(ch < '0' || ch > '9') {
ch = getchar();
}
while(ch >= '0' && ch <= '9') {
x = x * 10 + ch - '0';
ch = getchar();
}
return x;
}
const int maxn = 200;
ll factor[maxn];
int tol;
const int S = 8;
inline ll mult_mod(ll a,ll b,ll c){
a %= c;
b %= c;
ll ret = 0;
ll tmp = a;
while(b){
if(b & 1) {
ret += tmp;
if(ret > c) ret -= c;
}
tmp <<= 1;
if(tmp > c) tmp -= c;
b >>= 1;
}
return ret;
}
inline ll pow_mod(ll a,ll n,ll mod){
ll ret = 1;
ll tmp = a % mod;
while(n){
if(n & 1) ret = mult_mod(ret,tmp,mod);
tmp = mult_mod(tmp,tmp,mod);
n >>= 1;
}
return ret;
}
inline bool check(ll a,ll n,ll x,ll t){
ll ret = pow_mod(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;
else return false;
}
inline 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++;
}
srand(time(NULL));
for(int i = 0;i < S;i++){
ll a = rand() % (n - 1) + 1;
if(check(a,n,x,t)) return false;
}
return true;
}
inline ll gcd(ll a,ll b){
ll t;
while(b){
t = a;
a = b;
b = t % b;
}
if(a >= 0) return a;
else return -a;
}
inline ll pollard_rho(ll x,ll c){
ll i = 1,k = 2;
srand(time(NULL));
ll x0 = rand() % (x - 1) + 1;
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,int k){
if(n == 1) return;
if(Miller_Rabin(n)) {
factor[tol++] = n;
return;
}
ll p = n;
int c = k;
while(p >= n) p = pollard_rho(p,c--);
findfac(p,k);
findfac(n / p,k);
}
inline ll get(ll x,ll p){
ll cnt = 0;
while(x){
cnt += x / p;
x /= p;
}
return cnt;
}
int main(){
int T = rd();
while(T--){
tol = 0;
memset(factor,0,sizeof factor);
int n = rd();
ll x = rd();
ll y = rd();
vector<ll> v(n);
for(int i = 0;i < n;i++)
v[i] = rd();
findfac(x,107);
map<ll,ll> mp;
for(int i = 0;i < tol;i++){
mp[factor[i]]++;
}
ll ans = 4e18;
for(auto it:mp){
ll cnt = 0;
for(auto itt:v)
cnt += get(itt,it.fi);
ans = min(ans,(get(y,it.fi) - cnt) / it.se);
}
printf("%lld\n",ans);
}
}