zoukankan      html  css  js  c++  java
  • 快速质因数分解及素性测试&ABC142D

    首先,这个整数的标准分解非常的显然易见对吧:

     一般我们要把一个数分解成这个样子我们可以这样写:

     1 #include<cstdio>
     2 int p[105],w[105],k;
     3 void factorize(int n)
     4 {
     5     for(int i=2;i*i<=n;i++)
     6         if(n%i==0)
     7         {
     8             p[++k]=i;
     9             while(n%i==0)
    10                 n/=i,w[k]++;
    11         }
    12     if(n!=1)
    13         p[++k]=n,w[k]=1;
    14 }
    15 int main()
    16 {
    17     int n;
    18     scanf("%d",&n);
    19     factorize(n);
    20     for(int i=1;i<k;i++)
    21         printf("%d^%d*",p[i],w[i]);
    22     printf("%d^%d",p[k],w[k]);
    23 }

    由于是分解质数,而且质数除了2之外都是奇数,所以可以在枚举i的时候每次i+=2

    例题:ABC142D(手边没有什么好题了,只是因为最近做到了它2333)

    要找互质的公因数,就相当于找最大公因数的最多互质的因数。(这个表述...相信你们能懂

    之前写一直T了,于是找了另外一种方法,后面才发现之前的哪里有问题

     1 #include<cstdio>
     2 #include<algorithm>
     3 #include<map>
     4 using namespace std;
     5 #define N 100005
     6 #define ll long long
     7 #define MOD 1000000007
     8 ll x,y;
     9 map<ll,bool> vis;
    10 ll p[N];
    11 int pn;
    12 ll gcd(ll a,ll b)
    13 {
    14     if(b==0) return a;
    15     else return gcd(b,a%b);
    16 }
    17 int main()
    18 {
    19     scanf("%lld %lld",&x,&y);
    20     ll d=gcd(x,y);
    21     int ans=1;
    22     if(d%2==0) ans++;
    23     while(d%2==0)
    24         d/=2;
    25     for(ll i=3;i*i<=d;i+=2)//写成i<=d/i就可以不开ll 否则不开ll就会乘爆 然后T掉 
    26         if(d%i==0)
    27         {
    28             ans++;
    29             while(d%i==0)
    30                 d/=i;
    31         }
    32     if(d!=1) ans++;
    33     printf("%d
    ",ans);
    34     return 0;
    35 }

    就是我注释的那个地方,要注意那样的BUG了

    最后采用了这种写法:

     1 #include<cstdio>
     2 #include<algorithm>
     3 #include<map>
     4 #include<vector>
     5 #include<cmath>
     6 using namespace std;
     7 #define N 100005
     8 #define ll long long
     9 #define MOD 1000000007
    10 ll x,y;
    11 map<ll,bool> vis;
    12 ll p[N];
    13 int pn;
    14 vector<ll>st;
    15 ll gcd(ll a,ll b)
    16 {
    17     if(b==0) return a;
    18     else return gcd(b,a%b);
    19 }
    20 bool is_prime(ll x)
    21 {
    22     if(x==1) return 0;
    23     if(x==2||x==3) return 1;
    24     if(x%6!=1&&x%6!=5) return 0;
    25     int s=sqrt(x);
    26     for(int i=5;i<=s;i+=6)
    27         if(x%i==0||x%(i+2)==0)
    28             return 0;
    29     return 1;
    30 }
    31 int solve(ll n)
    32 {
    33     int ans=1;
    34     if(n==1) return 1;
    35     ll i=0;
    36     while(i<n)
    37     {
    38         if(is_prime(n))
    39         {
    40             st.push_back(n);
    41             if(vis[n]==0)ans++;
    42             vis[n]=1;
    43             return ans;
    44         }
    45         for(int i=2;i<n;i++)
    46         {
    47             if(n%i==0)
    48             {
    49                 st.push_back(i);
    50                 if(vis[i]==0)ans++;
    51                 vis[i]=1;
    52                 n/=i;
    53                 break;
    54             }
    55         }
    56     }
    57     st.push_back(n);
    58     if(vis[n]==0)ans++;
    59     vis[n]=1;
    60     return ans;
    61 }
    62 int main()
    63 {
    64     scanf("%lld %lld",&x,&y);
    65     ll d=gcd(x,y);
    66     printf("%d
    ",solve(d));
    67     return 0;
    68 }

    其实感觉和上面的做法差不多,直接看也就能看懂,但是网上据说是$n^{1/4}$的复杂度,那么还是了解一下,也没有什么坏处。(对于这道题来说其实不需要存因数的啦)

    关于is_prime的素数判断,还是说一下吧。

    如果不加这个判断,那么在$n$变成一个很大的质数的时候,这个算法就会退化到$O(n)$级别。

     

    对于每一个$>=5$的数可以表示为$6x-1$(也相当于$6x+5$),$6x$,$6x+1$,$6x+2$,$6x+3$,$6x+4$,$6x+5$中的一种。

    而$6x$,$6x+2=2(3x+1)$,$6x+3=3(x+1)$,$6x+4=2(3x+2)$,都不可能是素数。

    所以我们对于一个数n,直接先判断它模$6$是否余$5$或余$1$,不是的话直接返回false

    但是是的话也不一定是素数,还要再判断一下。

    每个数都能进行质因数分解,所以我们只要判断用它除前面的素数能否除尽就可以了.

    $6x+1$,$6x+5$这样的数显然不可能除的尽$2$和$3$,所以我们从$5$开始判断。

    下一个除以$7$,按照上面的讨论,下一个为$11$和$13$。

    网上有人说,以此类推,可以把步长增加到$6$来加快运行速度。

    不知道怎么证明,但是验证了一下是对的。(怎么感觉好水...)

    update2019.10.9 关于把步长增加到$6$

    发现自己好傻啊

    前面已经说了,3以后的质数都是除以6余1或者5的数

    那么连续的两个质数差为2

    当然,除以6余1或者5的数不一定都是质数,不过这没有关系,我们不一定要让除数是一个质数。


    莫名其妙地就干完了这篇博客。

    写得好水呀。

    嘤嘤嘤我在干什么。

    转载请注明出处,有疑问欢迎探讨 博主邮箱 2775182058@qq.com
  • 相关阅读:
    Oracle 多版本控制
    texedo 分布式事务
    OLAP 大表和小表并行hash join
    分页SQL模板
    全表扫描分页
    索引的结构图
    利用函数索引优化<>
    分页SQL取下一页
    SORT ORDER BY STOPKEY
    压缩跟踪(CT)代码具体学习_模块1(样本的採集和扩充)
  • 原文地址:https://www.cnblogs.com/lyttt/p/11621727.html
Copyright © 2011-2022 走看看