ICPC2019 Xuzhou E. Multiply Pollard_Rho 大数分解
题意
给出(n)个数(a_i),令(Z = prod a_i!)
给出(X,Y),令(b_i = Z imes 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 imes 2d imes 3d...lfloorfrac{n}{d}
floor d) imes a\
= d^{lfloorfrac{n}{d}
floor} imes lfloorfrac{n}{d}
floor! imes 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
",ans);
}
}