zoukankan      html  css  js  c++  java
  • 数(数学)

    数(数学)

    给出n(<=300)个数(<=1e18),它们的乘积是x。对于任意(d_imid x),有(d_i^{k_i} mid x,d_i^{k_i+1} mid x),求最大的(k_i),并输出当(k_i)最大时,有多少个(d_i)满足条件。

    首先,这道题的思路肯定是对x分解质因数,也就是对n个数分解质因数,然后求出质因数的最多出现次数c,和出现次数最多的质因数个数d,答案分别是(c)(2^d)

    现在问题来了,给出的一个数最多可以到(10^{18}),怎么分解质因数呢?先把小于1e6的质数都筛出来,把它们对这n个数试除。除完了以后,n个数中,没有数的因子小于1e6。因此,每个数x最多由两个质数相乘。

    到这一步以后,我们就可以通过两两gcd把出现一次以上的质因子确定出来。剩下的数中的质因子,肯定只会在自己那个数中出现。因此,通过(sqrt{n}^2)的方法和Miller-Rabin算法,就可以判断出这个数是由单独一个质因子组成,还是由两个相同质因子组成,抑或是由两个不同质因子组成。对于只出现过一次的质因子,我们并不关心它的值。

    #include <cmath>
    #include <cstdio>
    #include <algorithm>
    using namespace std;
    
    typedef long long LL;
    
    //////Miller-Rabin素数判定//////
    const LL m=7, A[m]={2, 3, 5, 7, 11, 13, 17};
    LL fmul(LL a, LL b, LL p){  //将b分解为二进制,返回a*b%p
        LL ans=0;
        for (; b; b>>=1, a+=a, a%=p)
            if (b&1) ans+=a, ans%=p;
        return ans;
    }
    LL fpow(LL a, LL x, LL p){
        LL ans=1, base=a;
        for (; x; x>>=1, base=fmul(base, base, p))
            if (x&1) ans=fmul(ans, base, p);
        return ans;
    }
    bool MR(LL a, LL x, LL p){  //判断是否a^x=1或p-1 (mod p),且mr下去也成立
        LL t=fpow(a, x, p);
        if (t!=1&&t!=p-1) return false;
        if (t==1&&x&1||t==p-1) return true;
        return MR(a, x>>1, p);
    }
    bool isprime(LL p){
        if (p&1==0) return false;
        for (LL i=0; i<m; ++i){
            if (p==A[i]) return true;  //互质时费马小定理才成立
            if (fpow(A[i], p-1, p)!=1) return false;
            if (!MR(A[i], (p-1)>>1, p)) return false;
        }
        return true;
    }
    
    const LL maxn=305, maxs=1e6+5;
    LL n, a[maxn], tmp[maxn], tmpn, c[maxn];
    
    LL p[maxs], cntp, factor[maxs];
    void sieve(LL n){
        for (LL i=2; i<n; ++i){
            if (factor[i]) continue;
            p[cntp++]=i;
            for (LL j=i; j<n; j+=i) factor[j]=i;
        }
    }
    
    LL allp[maxn*60], tl;
    LL b[maxn*maxn], tl2;  //extrap1:没有被列入allp的,出现次数为1的质数还有多少个
    LL appear[maxn*60];
    
    LL gcd(LL x, LL y){ return y?gcd(y, x%y):x; }
    LL sqr(LL x){ return x*x; }
    LL x[maxn*2];
    
    int main(){
        //freopen("number.in", "r", stdin); freopen("number.out", "w", stdout);
        sieve(1e6);
        scanf("%lld", &n);
        for (LL i=0; i<n; ++i){
            scanf("%lld", &a[i]);
            for (LL j=0; j<cntp; ++j)
                while (a[i]%p[j]==0){
                    a[i]/=p[j]; allp[tl++]=p[j]; }
        }
        for (int i=0; i<n; ++i) tmp[i]=a[i]; tmpn=n;
        sort(a, a+n);  n=unique(a, a+n)-a;
        for (int i=0; i<n; ++i)  //对a去重,保存重复个数
            for (int j=0; j<tmpn; ++j) if (a[i]==tmp[j]) ++c[i];
        for (LL i=0; i<n; ++i)
            for (LL j=0; j<n; ++j)
                if (a[i]!=a[j]) b[tl2++]=gcd(a[i], a[j]);
        sort(b, b+tl2); tl2=unique(b, b+tl2)-b;  //1和所有大于1e6且在至少两个数上出现的质数 tl2最多到2n
        for (LL i=0; i<n; ++i)  //把所有能分解的数都分解了,剩下的数,素因子一定只有自己有
            for (LL j=0; j<tl2; ++j){
                if (b[j]==1) continue;
                if (a[i]%b[j]==0){
                    while (c[i]--) allp[tl++]=b[j],
                        allp[tl++]=a[i]/b[j];
                    a[i]=1;
                }
            }
        for (LL i=0; i<n; ++i){
            if (a[i]==1) continue;
            if (sqr(sqrt(a[i]))==a[i]){  //如果A=a*a
                a[i]=sqrt(a[i]);
                while (c[i]--) allp[tl++]=a[i], allp[tl++]=a[i];
                continue;
            }
            if (isprime(a[i])) ++appear[c[i]]; else appear[c[i]]+=2;
        }
        sort(allp, allp+tl); LL j=1, maxm=0;
        for (LL i=1; i<tl; ++i, ++j){  //appear[j]:j次的素数有多少个
            if (allp[i]!=allp[i-1]){
                if (allp[i-1]!=1) ++appear[j];
                j=0;
            }
        }
        if (tl) ++appear[j];
        for (maxm=maxn*60-1; maxm>=0; --maxm) if (appear[maxm]) break;
        printf("%lld
    ", maxm); x[0]=1;
        for (LL i=0; i<appear[maxm]; ++i){
            for (LL j=0; j<maxn*2; ++j) x[j]*=2;
            for (LL j=0; j<maxn*2-1; ++j) x[j+1]+=x[j]/10, x[j]%=10;
        } LL len;
        for (len=maxn*2-1; len>=0; --len) if (x[len]) break;
        --x[0];
        for (LL i=0; i<maxn*2; ++i) if (x[i]<0) x[i]+=10, --x[i+1];
        for (LL i=len; i>=0; --i) printf("%lld", x[i]);
        //fclose(stdin); fclose(stdout);
        return 0;
    }
    
  • 相关阅读:
    Codeforces Global Round 7 题解 (ABCDE)
    猫树 简单介绍
    pip模块
    协程
    多线程threading
    多进程multiprocessing
    DOM
    标签学习
    初步了解Bootstrap4
    初步了解jQuery
  • 原文地址:https://www.cnblogs.com/MyNameIsPc/p/9319328.html
Copyright © 2011-2022 走看看