Miller-Rabin + Pollard-rho
阿新 • • 發佈:2022-05-08
Miller-Rabin + Pollard-Rho演算法模板題2019 ACM-ICPC Asia Xuzhou E
題意:給一個大小為\(n\)的序列a,定義$ Z = \Pi_{i=1}^{n} a_i$。另給出 \(X ,Y\),若\(b_i = Z * X^{i}\),求最大的\(i\)使得\(b_i | Y!\)。
題解:板子題,題解略。
#include<bits/stdc++.h> using namespace std; #define rep(i,a,b) for(int i=(a);i<(b);i++) #define per(i,a,b) for(int i=(b)-1;i>=(a);i--) #define pb push_back #define db double #define VI vector<int> #define ll long long #define ld long double #define ull unsigned long long #define PII pair<int,int> #define fi first #define se second mt19937_64 mrand(random_device{}()); ll rnd(ll x){return mrand()%x;} #define all(x) x.begin(),x.end() ll gcd(ll a,ll b){return !b?a:gcd(b,a%b);} const ll mod = 1e9+7; ll qpow(ll a,ll b){ll t=1;assert(b>=0);for(;b;b>>=1){if(b&1)t=t*a%mod;a=a*a%mod;}return t;} //時間複雜度7*log^3(n) ll qmul(ll a,ll b,ll mod)//快速乘 { ll c=(ld)a/mod*b; ll res=(ull)a*b-(ull)c*mod; return (res+mod)%mod; } ll qpow(ll a,ll n,ll mod)//快速冪 { ll res=1; while(n) { if(n&1) res=qmul(res,a,mod); a=qmul(a,a,mod); n>>=1; } return res; } bool MRtest(ll n)//Miller Rabin Test { if(n<3||n%2==0) return n==2;//特判 ll u=n-1,t=0; while(u%2==0) u/=2,++t; //ll ud[] = {2,7,61}; ll ud[]={2,325,9375,28178,450775,9780504,1795265022}; for(ll a:ud) { ll v=qpow(a,u,n); if(v==1||v==n-1||v==0) continue; for(int j=1;j<=t;j++) { v=qmul(v,v,n); if(v==n-1&&j!=t){v=1;break;}//出現一個n-1,後面都是1,直接跳出 if(v==1) return 0;//這裡代表前面沒有出現n-1這個解,二次檢驗失敗 } if(v!=1) return 0;//Fermat檢驗 } return 1; } //找到n的一個因子,時間複雜度是O(n^(1/4)) //結合Miller-Rabin可用來求出最大素因子 //模板題:https://www.luogu.com.cn/problem/P4718 //進一步優化可以考慮倍增和固定上限結合 ll Pollard_Rho(ll N){ if (N == 4)return 2; if (MRtest(N))return N; while(1){ ll c = rnd(N-1) + 1; auto f = [=](ll x) { return ((__int128)x * x + c) % N; }; ll t = 0, r = 0, p = 1, q; do{ for (int i = 0; i < 128; ++i){ // 令固定距離C=128 t = f(t), r = f(f(r)); if (t == r || (q = (__int128)p * abs(t - r) % N) == 0) // 如果發現環,或者積即將為0,退出 break; p = q; } ll d = gcd(p, N); if (d > 1)return d; }while (t != r); } } ll max_prime_factor(ll x){ ll fac = Pollard_Rho(x); if (fac == x)return x; else return max(max_prime_factor(fac), max_prime_factor(x / fac)); } const int N = 1e5+5; ll a[N],x,y; int n; ll fac[30],idx; int fac_cnt[30]; void chai(ll x){ while(x!=1){ ll temp = max_prime_factor(x); fac[++idx] = temp; while(x%temp==0){ fac_cnt[idx]++; x/=temp; } } } ll cal(ll n,ll p){ ll res = 0; while(n){ res += n/p; n/=p; } return res; } ll solve(){ ll ans = 4e18; for(int i=1;i<=idx;i++){ ll& p = fac[i]; ll ty = cal(y,p); for(int j=1;j<=n;j++){ ty -= cal(a[j],p); } ans = min(ans,ty/fac_cnt[i]); } return ans; } int main(){ int t;cin >> t; while(t--){ idx = 0; memset(fac_cnt,0,sizeof fac_cnt); scanf("%d%lld%lld",&n,&x,&y); for(int i=1;i<=n;i++)scanf("%lld",a+i); chai(x); ll ans = solve(); cout << ans << endl; } }