zoukankan      html  css  js  c++  java
  • 逆元与素数

    A - Detachment

    题目:http://acm.hdu.edu.cn/showproblem.php?pid=5976

    题解:这道题思路为:数学规律+逆元

    这里有一个结论,对于一个数把他拆成从2开始的连续的数,最后得到的成绩是最大的,所以我们可以先预处理一下前缀和包括乘积后的结果。不过对于有些数无法用多个连续的数表示,比如对于11可以找到2+3+4,此时还余2,要构成5还差3,所以我们把3变成5即2 + 4 + 5.

    之前是2+3+4

    现在是2+4+5
    但有种特殊情况,比如2+3+.. + l,此时还余个l,因此我们会为前l-1个数都加上1,还剩余一个1就加到最后一个数,

    之前是2+3+4+...l,现在是3+4+5+6+...l+(l+2),对比两者的变化,相当于除去2,在乘上l+2,由于我们要进行取余,因此除法的操作就需要用到逆元(由费马小定理)

    代码:

    #include<iostream>
    #include<cstdio>
    using namespace std;
    typedef long long ll;
    const ll mod=1e9+7;
    const int N=50010;
    ll sum[N],f[N];
    void init()
    {
        f[1]=1;
        for(int i=2;i<=N;i++)
        {
            sum[i]=sum[i-1]+i;
            f[i]=(f[i-1]*i)%mod;
        }
    }
    
    ll pow_s(ll a, ll n)
    {
        ll res=1;
        while(n)
        {
            if(n&1)
                res=res%mod*a%mod;
            a=a%mod*a%mod;
            n>>=1;
        }
        return res;
    }
    
    int main()
    {
        ll i,j,t,x;
        scanf("%lld",&t);
        init();
        while(t--)
        {
            scanf("%lld",&x);
            if(x<=4)
            {
                printf("%lld
    ",x);
                continue;
            }
            //二分法找到适合的l
            ll l=0,r=N;
            while(r-l>1)
            {
                ll mid=l+(r-l)/2;
                if(sum[mid]>x)
                    r=mid;
                else
                    l=mid;
            }
            ll leve=x-sum[l];
            ll res=f[l];
            if(leve==l)
                res=(res*pow_s(2,mod-2)%mod*(l+2))%mod;
            else
                res=(res*pow_s(l+1-leve,mod-2)%mod*(l+1))%mod;
            printf("%lld
    ",res);
        }
        return 0;
    }

    B - 寻找素数对

    题目:http://acm.hdu.edu.cn/showproblem.php?pid=1262

    题解:从这个数的一半的地方开始找,然后进行素数判断,循环即可实现

    代码:

    #include<iostream>
    #include<algorithm>
    #include<cmath>
    #include<cstdio>
    using namespace std;
    int m;
    
    bool check(int s)
    {
        for(int i=2;i<=sqrt(s);i++)
        {
            if(s%i==0)
                return false;
        }
        return true;
    }
    
    int main()
    {
        int i,j;
        while((scanf("%d",&m))!=EOF)
        {
            int k=m/2;
            for(i=k;i>0;i--)
            {
                int f=m-i;
                if(check(f)&&check(i))
                {
                    cout<<i<<" "<<f<<endl;
                    break;
                }
            }
        }
        return 0;
    }

    C - Max Factor

    题目:http://acm.hdu.edu.cn/showproblem.php?pid=2710

    题解:寻找最大的素数因子,我们可以利用埃式筛求素数的方法,打表找到所有数的最大的素数因子,然后进行比较选出最终的结果。

    代码:

    #include<iostream>
    #include<cmath>
    using namespace std;
    const int MAXN=1e5;
    int prime[MAXN+1];
    int v[20010];
    void aisoup()
    {
        for(int i=0;i<=20010;i++)
            v[i]=1;
        for(int i=2;i<=20010;i++)
        {
            if(v[i]==1)
            {
                for(int j=i;j<=20010;j+=i)
                    v[j]=i;
            }
        }
    }
    
    int main()
    {
        int i,j,n,x,ans,maxn=-1;
        aisoup();
        while(cin>>n)
        {
            ans=0;
            maxn=-1;
            for(int i=0;i<n;i++)
            {
                cin>>x;
                if(v[x]>maxn)
                {
                    maxn=v[x];
                    ans=x;
                }
            }
            cout<<ans<<endl;
        }
        return 0;
    }

    D - Twin Prime Conjecture

    题目:http://acm.hdu.edu.cn/showproblem.php?pid=3792

    题解:题目的意思是找出小于等于他的相邻素数对相差为2的对数,一开始直接利用埃式筛求出素数,然后对于每个数进行一次计算,最终TLE了。

    明显这样太过于浪费时间,存在重复计算,因此我们对其进行打表,算出ans数组,它对应的为相应数的素数对个数,而他们之间的关系为,i和i-1之间,比较二者对应的数与相差为2的数是否都为素数。

    代码:

    #include<iostream>
    using namespace std;
    const int N=1e5+10;
    int prime[N];
    bool v[N];
    int ans[N];
    void pre()
    {
        int k=0;
        for(int i=2;i<N;i++)
        {
            if(!v[i])
            {
                prime[k++]=i;
                for(int j=2*i;j<N;j+=i)
                {
                    v[j]=true;
                }
            }
        }
    }
    void f()
    {
        pre();
        ans[1]=ans[2]=ans[3]=0;
        for(int i=4;i<N;i++)
        {
            if(!v[i]&&!v[i-2])
            {
                ans[i]=ans[i-1]+1;
            }
            else
                ans[i]=ans[i-1];
        }
    }
    int main()
    {
        f();
        int n,i,j;
        while(cin>>n)
        {
            if(n<0)
                break;
            cout<<ans[n]<<endl;
        }
        return 0;
    }

    E - Squarefree number

    题目:http://acm.hdu.edu.cn/showproblem.php?pid=3826

    题解:这道题相对来说比较有难度,判断该数的因子当中是否有平方数。我们素数的筛选范围在106范围内,对于这个数的范围为1016次方。

    输入一个n,如果可以被一个平方数整除,则不是平方自由数,输出no,否则输出yes
    分析:显然要分解质因数,根据唯一分解定理分解。
    n<=10^18,不能用暴力求到10^9的素数,欧拉筛一般只是找10^6内的素数。显然需要优化。
    如果n>10^6,巨大,筛完了10^6内的质因子后,n还是大于10^6,则
    1.如果n不是平方自由数,则因子中包含质因数的平方,则n=p*p,p是素数,p>10^6,除此之外没有别的大于10^6的因子了,否则n>10^18
    2.如果n是平方自由数,则因子中不包含质因数的平方
    (1)n是素数
    (2)n不是素数,n=p1*p2,是两个大素数的乘积。p1,p2>10^6
     
    代码:
    #include<iostream>
    #include<cmath>
    #include<cstdio>
    using namespace std;
    typedef long long ll;
    const int N=1e6+10;
    ll t,n;
    int prime[N];
    bool v[N];
    int k;
    void pre()
    {
        k=0;
        for(int i=2;i<N;i++)
        {
            if(!v[i])
            {
                prime[k++]=i;
                for(int j=i*2;j<N;j+=i)
                    v[j]=true;
            }
        }
    }
    int main()
    {
        ll i,j;
        cin>>t;
        pre();
        for(i=1;i<=t;i++)
        {
            cin>>n;
            bool flag=false;
            for(j=0;j<k;j++)
            {
                int sum=0;
                while(n%prime[j]==0)
                {
                    n/=prime[j];
                    sum++;
                }
                //sum>=2表示有平方数
                if(sum>=2)
                {
                    flag=true;
                    break;
                }
            }
            if(!flag&&n>1)
            {
                //判断是否为两个一样大的素数相乘
                ll s=sqrt(n);
                if(s*s==n)
                    flag=true;
            }
            if(flag)
                printf("Case %d: No
    ",i);
            else
                printf("Case %d: Yes
    ",i);
        }
        return 0;
    }
  • 相关阅读:
    ADO数据库操作
    AfxMessageBox和MessageBox区别
    Qt — 子窗体操作父窗体中的方法
    Qt — tableWidget插入复选框
    Qt & MySQL
    windows下安装Qt
    Extjs — Grid数据导出成Excel
    Mac终端 vi/vim 的简单使用
    iOS开发CocoaPods使用说明
    Shell 脚本学习笔记十:Shell输入输出重定向
  • 原文地址:https://www.cnblogs.com/xiaofengzai/p/13220905.html
Copyright © 2011-2022 走看看