判断是否为素数 + 分解质因数(利用了Miller_Rabin和素数筛选法)

来源:互联网 发布:java培训哪个机构最好 编辑:程序博客网 时间:2024/05/16 06:06

http://acm.hdu.edu.cn/showproblem.php?pid=5778

题意:T组数据,给x求y。y满足个条件1.与x差的绝对值最小    2.质因数分解每个元素恰好出现两次。x <= 10 ^18

解析:直接枚举sqrt(y),先判断开方后的这个数是否为素数(利用logn的算法),如果不是判断。开方后的这个数中分解质因数的因数每个元素最多出现一次,暴力枚举即可

另:要注意题目中的条件y >= 2

代码:

#include <iostream>#include <cstdio>#include <cstring>#include <sstream>#include <string>#include <algorithm>#include <list>#include <map>#include <vector>#include <queue>#include <stack>#include <cmath>#include <cstdlib>using namespace std;#define maxn (100000 + 50)typedef long long LL;LL fabs2(long long x){    if(x < 0)        return -x;    return x;}//接口:if(Miller_Rabin(n) == true)//为真则为素数bool isPrime[maxn];LL primeList[maxn],primeCount = 0;void primeInit(LL n){    memset(isPrime,true,sizeof(isPrime));//初始化认为全部是素数    int m = sqrt(n + 0.5);    for(int i = 2; i <= m;  i ++)    {        if(isPrime[i])//判断是素数        {            for(int j = i * i; j <= n; j += i){               isPrime[j] = false;            }        }    }    for(int i = 2; i <= n; i ++)    {        if(isPrime[i]){        primeList[primeCount] = i;                primeCount ++;        }    }}const int S=20;//随机算法判定次数,S越大,判错概率越小long long mult_mod(long long a,long long b,long long c){    a%=c;    b%=c;    long long ret=0;    while(b)    {        if(b&1)        {            ret+=a;            ret%=c;        }        a<<=1;        if(a>=c)a%=c;        b>>=1;    }    return ret;}//计算  x^n %clong long pow_mod(long long x,long long n,long long mod)//x^n%c{    if(n==1)return x%mod;    x%=mod;    long long tmp=x;    long long ret=1;    while(n)    {        if(n&1) ret=mult_mod(ret,tmp,mod);        tmp=mult_mod(tmp,tmp,mod);        n>>=1;    }    return ret;}//以a为基,n-1=x*2^t      a^(n-1)=1(mod n)  验证n是不是合数//一定是合数返回true,不一定返回falsebool check(long long a,long long n,long long x,long long t){    long long ret=pow_mod(a,x,n);    long long last=ret;    for(int i=1; i<=t; i++)    {        ret=mult_mod(ret,ret,n);        if(ret==1&&last!=1&&last!=n-1) return true;//合数        last=ret;    }    if(ret!=1) return true;    return false;}// Miller_Rabin()算法素数判定//是素数返回true.(可能是伪素数,但概率极小)//合数返回false;bool Miller_Rabin(long long n){    if(n<2)return false;    if(n==2)return true;    if((n&1)==0) return false;//偶数    long long x=n-1;    long long t=0;    while((x&1)==0)    {        x>>=1;        t++;    }    for(int i=0; i<S; i++)    {        long long a=rand()%(n-1)+1;//rand()需要stdlib.h头文件        if(check(a,n,x,t))            return false;//合数    }    return true;}int main(){//freopen("in.txt","r",stdin);    primeInit(100000);    int T;    scanf("%d",&T);    while(T--)    {        int tcnt = 0;        bool flag;        LL ans;        LL x;        long long left,right;        scanf("%I64d",&x);        left = sqrt(x) ;        right = sqrt(x) + 1 ;        int cnt = 0;        LL l,r;        while(1)        {            l =left + cnt;            if(l < 2)            {                cnt++;                continue;            }            if(Miller_Rabin(l) == true)//为真则为素数            {                ans = fabs2(l *l - x);                break;            }            flag = true;            for(int i = 0; i*i <= l && i < primeCount; i ++)            {                tcnt = 0;                while(l% primeList[i] == 0)                {                    l = l / primeList[i];                    tcnt ++;                }                if(tcnt > 1)                {                    flag = false;                    break;                }            }            if(flag == true)            {                ans = fabs2(x - (left + cnt) * (left + cnt));                break;            }             cnt ++;        }        cnt = 0;        while(1){            r = right - cnt;            if(r < 2)                break;            if(Miller_Rabin(r) == true)//为真则为素数            {                ans =min(ans, fabs2(r*r -x));                break;            }            flag = true;            for(int i = 0; i*i <= r&& i < primeCount; i ++)            {                tcnt = 0;                while(r% primeList[i] == 0)                {                    r = r / primeList[i];                    tcnt ++;                }                if(tcnt > 1)                {                    flag = false;                    break;                }            }            if(flag == true)            {                ans = min(ans,fabs2(x - (right - cnt) * (right - cnt)));                break;            }            cnt ++;        }        printf("%I64d\n",ans);    }    return 0;}


0 0
原创粉丝点击