• 18省夏day1


    1、素因数分解

           1、https://www.luogu.org/problemnew/show/P1075

           2、https://www.luogu.org/problemnew/show/CF776B:这道题显然可以将素数化为                         1,合数变为2,然后因为长度到了100000,所以应使用埃氏筛法。但实践是一直有问题,1、要注意i等于1和2的特例;2、

           3、整数惟一分解定理:任意一个大于0的正整数都能被表示成若干个素数的乘积且表示方法是唯一的;整理可以将相同素数的合并;可以得到公式————n = P1^a1 * P2^a2 * …………*Pn^an (P1 < P2 < ……Pn);有一些小细节要注意

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    using namespace std;
    int n;
    int a[10000];
    int p[10000]; 
    int main(){
        scanf("%d",&n);
        int m=n;//注意应用m代替n,不用中途会变小 
        int count=0;
        for(int i=2;i*i<=n;i++){
            while(m%i==0){//因为一定会把带有这个素数的除完,所以肯定不会被合数除 
                p[i]++;    //这样写好写方便 
                m/=i;
            }
        }
        if(m>1)p[m]++;//重点!!最后可能会多一个出来,要把本身也算 
        for(int i=2;i<=n;i++)
            if(p[i])
                printf("%d^%d
    ",i,p[i]);
    }
    View Code

     2、素数筛法

           1、埃氏筛法 埃氏筛法的中心还是很好理解,只是要注意从j=i*i开始,降低时间消耗

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    using namespace std;
    int n,a[1001001];
    int main(){
        scanf("%d",&n);
        a[0]=a[1]=1;//将0和1特判,素数 为0
        for(int i=2;i*i<=n;i++){
            if(!a[i]){
                for(int j=i*i;j<=n;j+=i)
                    a[i]=1;
            }
        } 
        for(int i=2;i<=n;i++){
            printf("%d ",a[i]);
        }
        return 0;
    } 
    View Code 

           2、Prime Distance:https://www.luogu.org/problemnew/show/UVA10140   这道题还是应用埃氏筛法,但是这道题显然数据太大,不能筛完全部素数,所以我们可以考虑先筛出2到根号r的所有素数(为了节省时间,要先做,直接到100000>根号的2^31-1),然后注意到l和r间的的范围是有限的,只有1000000,所以就用已算出的素数将其筛掉,即标记i*p-l 为合数(减去l是精华!,然后再用prime2将l到r的素数记录下来即可。

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    using namespace std;
    int prime1[100100];
    long long prime2[100100];//注意大小,要用ll 
    bool check[1000100];//用bool占用的空间较小 
    int count1=1,count2;
    int main(){//往往错在最没想到会错的地方 
        for(int i=2;i*i<=100100;i++)
            if(!check[i]){//写错 
                prime1[count1++]=i;
                for(long long j=i*i;j<=100100;j+=i)//j应+=i 
                    check[j]=1;//写错 
            }    
    /*    for(int i=1;i<=10;i++)
            cout<<prime1[i]<<"   ";*/
        long long L,R;    
        long long mina,maxa,x1,x2,y1,y2;
        while(scanf("%lld%lld",&L,&R)!=EOF){
            mina=131313133,maxa=-1;
            x1=x2=y1=y2=0;
            memset(check,0,sizeof(check));
            count2=0;
            L=max(L,(long long)2);//要注意1是特例 
            for(long long i=1;prime1[i]*prime1[i]<=R&&i<count1;i++){//注意在prime1中素数只有count1个 
                long long s=L/prime1[i]+(L%prime1[i]>0);//括号位置!因为范围在L,R间l/prime向下取整,除非正好相等否则要加1 
                if(s==1)s=2;//因为prime本身是素数,如果*1也还是素数,如果从1开始就会把素数判成合数 
                for(long long j=s;j*prime1[i]<=R;j++)//j*prime[i]只有小于r才有意义 
                    check[j*prime1[i]-L]=1;
            }
        /*    for(int i=0;i<335;i++)
                printf("%d  ",check[i]);*/
            for(long long i=0;i<=R-L;i++)//重点,i的取值范围,l可能正好是素数,最多到R-l 
                if(!check[i])prime2[count2++]=i+L;//count2记区间有几个素数 
        /*    for(int i=0;i<count2;i++)
                printf("%d  ",prime2[i]);*/
            for(int i=1;i<count2;i++){
                if(prime2[i]-prime2[i-1]<mina){
                    mina=prime2[i]-prime2[i-1];
                    x1=prime2[i-1],y1=prime2[i];
                }
                if(prime2[i]-prime2[i-1]>maxa){
                    maxa=prime2[i]-prime2[i-1];
                    x2=prime2[i-1],y2=prime2[i];
                }
            }
            if(count2<2)
                printf("There are no adjacent primes.
    ");
            else{
                printf("%lld,%lld are closest, %lld,%lld are most distant.
    ",x1,y1,x2,y2);
            }
        }
        return 0;                
    }
    View Code

          3.利用埃氏筛法优化质因数分解,只要找到在判素数时同时找到最小素因数即可

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<vector>
    using namespace std;
    int prime[1001000],minf[1001000];//确定最小质因数 
    vector<int > ret;
    //做确定素数时要考虑取值范围,是否要用long long来定义 
    void erato(int n){
        prime[0]=prime[1]=0;
        minf[0]=0;minf[1]=1;//特例 
        for(int i=2;i<=n;i++)
            prime[i]=1,minf[i]=i;//当他本身是最小的要么是素数,要么还没找到 
        for(int i=2;i*i<=n;i++)
            if(prime[i]){
                for(int j=i*i;j<=n;j+=i){
                    prime[j]=0;
                    if(minf[j]=j)
                        minf[j]=i;
                }
            }
    }
    int found(int x){
        while(x>1){
            ret.push_back(minf[x]);
            x/=minf[x];
        }
    }
    int main(){
        int n;
        scanf("%d",&n);
        erato(n);
        found(n);
        return 0; 
    }
    View Code

          4.阶乘分解:将阶乘n!(1<=n<=10^6)分解素因数,以唯一分解形式给出pi和ri                朴素想法将1~n质因数分解,再将相同的pi累加,但是这样显然过不了

    然后我们考虑,其实在1~n中,素数也就那几个,所以先找出全部的素数,然后对于每个素数,,N/p^k向下取整就是p出现的个数(通过举例可验证或,因为在n内,对于p的倍数有n/p个,如果有的是p^2的倍数,那么也出现n/p^2个,同理可证)

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    using namespace std;
    int n,prime[10010],cs[10010],f[1010010];
    int cnt=1;
    void foun(){
        for(int i=2;i<=n;i++){
            if(!f[i]){
                prime[cnt]=i;cnt++;
                for(int j=i*i;j<=n;j+=i)
                    f[j]=1;
            }
        }
        cnt--;
    }
    void jl(){
        for(int i=1;i<=cnt;i++){
            for(int j=prime[i];j<=n;j*=prime[i])
                cs[i]+=n/j;
        }
    }
    int main(){
        scanf("%d",&n);
        foun();//先找出一到n中所有存在的质数 
        jl();//找每个素数被用的次数 
        for(int i=1;i<cnt;i++)
            printf("%d^%d+",prime[i],cs[i]);
        printf("%d^%d",prime[cnt],cs[cnt]);
    }
    View Code

          5.欧拉筛法(线性筛):利用 i 和素数表中的素数 prime[j] 去筛除 i*prime[j] ,为了确保i*prime[j] 只被素数 prime[j] 筛除过这一次,要确保 prime[j] 是i*prime[j] 中最小的素因子,即 i 中不能有比 prime[j] 还要小的素因子

    //线性筛法
    void Euler(){
        for(int i=2;i<=n;i++){
            if(!isprime[i])prime[++prime[0]]=i;
            else{
                for(int j=1;j<=prime[0]&&prime[j]*i<=n;j++){//每次用已确定的素数来筛 
                    isprime[prime[j]*i]=1;
                    if(i%prime[j]==0)break;//这句话是线性筛精华所在,保证每个数只被
                    //它最小的素因子筛去; 
                }
            }
        }
    } 
    View Code
  • 相关阅读:
    app被Rejected 的各种原因翻译
    UIView Border color
    Centos7下安装docker
    利用Yum彻底移除docker
    Docker删除全部镜像和容器
    【转】哈哈笑一笑
    【转】KAFKA分布式消息系统
    java读取properties文件
    java反序列化php序列化的对象
    Java 1.7.0_06中String类内部实现的一些变化【转】
  • 原文地址:https://www.cnblogs.com/linzeli/p/9291984.html
Copyright © 2020-2023  润新知