2020牛客暑期多校第四场 B - Basic Gcd Problem(质因数分解)

传送门


在这里插入图片描述
仔细观察这个式子,我们发现如果每次转移到 x x 的因数,会多乘一个 c c ,为了使答案更大,可以通过每次消掉 x x 的一个质因子,那么问题就变成了求 x x 的质因数个数,如果我们对每个 x x 质因数分解,时间复杂度为 O ( n n ) O(n*\sqrt{n}) ,这样会超时,那么可以使用Pollard Rho质因数分解,时间复杂度 O ( n n 1 4 ) O(n*n^{\frac{1}{4}})

#include <bits/stdc++.h>
#include <unordered_map>
using namespace std;
#define fi first
#define se second
#define pb push_back
#define ins insert
#define Vector Point
#define lowbit(x) (x&(-x))
#define mkp(x,y) make_pair(x,y)
#define mem(a,x) memset(a,x,sizeof a);
typedef long long LL;
typedef long double ld;
typedef unsigned long long ull;
typedef pair<int,int> pii;
typedef pair<double,double> pdd;
const double eps=1e-8;
const double pi=acos(-1.0);
const int inf=0x3f3f3f3f;
const double dinf=1e300;
const LL INF=1e18;
const int Mod=1e9+7;
const int maxn=2e5+10;

LL qkp(LL x,LL n,LL p){
    LL ans=1;
    while(n){
        if(n&1) ans=ans*x%p;
        x=x*x%p;
        n>>=1;
    }
    return ans;
}

struct BigIntegerFactor{
    const static int maxm = 1e6+16;
    LL prime[maxm],p[maxm],fac[maxm],sz,cnt;     //多组输入注意初始化cnt = 0
    inline LL mul(LL a,LL b,LL mod){             //WA了尝试改为__int128或慢速乘
        if(mod <= 1000000000) return a * b % mod;
        return (a*b-(LL)((long double)a/mod*b+1e-8)*mod+mod)%mod;
    }
    void init(int maxn){    //传入的参数不超过maxm,此题需要1e6
        int tot = 0; sz = maxn-1;
        for(int i = 1;i <= sz; ++i) p[i] = i;
        for(int i = 2;i <= sz; ++i){
            if(p[i] == i) prime[tot++] = i;
            for(int j = 0;j<tot&&1ll*i*prime[j]<=sz; ++j){
                p[i*prime[j]] = prime[j];
                if(i%prime[j] == 0) break;
            }
        }
    }
    LL powl(LL a,LL x,LL mod){
        LL res = 1LL;
        while(x){
            if(x&1) res = mul(res,a,mod);
            a = mul(a,a,mod);
            x >>= 1;
        }
        return res;
    }
    bool check(LL a,LL n){                       //二次探测原理检验n
        LL t = 0,u = n-1;
        while(!(u&1)) t++,u >>= 1;
        LL x = powl(a,u,n),xx = 0;
        while(t--){
            xx = mul(x,x,n);
            if(xx==1 && x!=1 && x!=n-1) return false;
            x = xx;
        }
        return xx == 1;
    }
    bool miller(LL n,int k){   //一般k取20即可
        if(n == 2) return true;
        if(n < 2 || !(n&1)) return false;
        if(n <= sz) return p[n] == n;
        for(int i = 0;i <= k; ++i){               //测试k次
            if(!check(rand()%(n-1)+1,n)) return false;
        }
        return true;
    }
    inline LL gcd(LL a,LL b){
        return b == 0 ? a : gcd(b,a%b);
    }
    inline LL Abs(LL x){
        return x < 0 ? -x : x;
    }
    LL Pollard_rho(LL n){                  //基于路径倍增的Pollard_Rho算法
        LL s = 0,t = 0,c = rand()%(n-1)+1,v = 1,ed = 1;
        while(1){
            for(int i = 1; i <= ed; ++i){
                t = (mul(t,t,n) + c) % n; v = mul(v,Abs(t-s),n);
                if(i % 127 == 0){
                    LL d = gcd(v,n);
                    if(d > 1) return d;
                }
            }
            LL d = gcd(v,n); if(d > 1) return d;
            s = t; v = 1; ed <<= 1;
        }
    }
    void getfactor(LL n){                          //得到所有的质因子(可能有重复的)
        if(n <= sz){
            while(n != 1) fac[cnt++] = p[n],n /= p[n];
            return;
        }
        if(miller(n,6)) fac[cnt++] = n;
        else{
            LL d = n; while(d >= n) d = Pollard_rho(n);
            getfactor(d); getfactor(n/d);
        }
    }
    LL solve(LL x){  //处理重复质因数
        map<LL,LL> mp;
        cnt = 0; getfactor(x);
        LL ans=0;
        for(int i = 0;i < cnt; ++i)
            mp[fac[i]]++;
        for(auto i: mp) ans+=i.se;
        return ans;
    }
}Q;

int main(){
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    //ios_base::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    LL c,x,t;
    Q.init(1000000);
    scanf("%lld",&t);
    while(t--){
        scanf("%lld%lld",&x,&c);
        printf("%lld\n",qkp(c,Q.solve(x),Mod));
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_44691917/article/details/107545947