Loading

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);
	}
}
posted @ 2021-05-10 16:07  MQFLLY  阅读(63)  评论(0编辑  收藏  举报