hdu-4344-Mark the Rope-大数分解质因子模板

#include<stdio.h>
#include<string.h>
#include<math.h>
#include<time.h>
#include<stdlib.h>
__int64 prime[]={2,3,5,7,11,13,17,19,23,29};
#define TIME 15    //Miller测试次数
__int64 gcd(__int64 a,__int64 b){return b==0?a:gcd(b,a%b);}                                            
__int64 mod_mult(__int64 a, __int64 b, __int64 n) //计算(a*b) mod n
{
    __int64 s = 0;
    a = a % n;
    while (b) {
        if (b & 1) {
            s += a;
            if (s >= n)
                s -= n;
        }
        a = a << 1;
        if (a >= n)
            a -= n;
        b = b >> 1;
    }

    return s;
}
__int64 mod_exp(__int64 a, __int64 b, __int64 n) //计算(a^b) mod n
{
    __int64 d = 1;
    a = a % n;
    while (b >= 1) {
        if (b & 1)
            d = mod_mult(d, a, n);
        a = mod_mult(a, a, n);
        b = b >> 1;
    }
    return d;
}

bool Wintess(__int64 a, __int64 n) //以a为基对n进行Miller测试并实现二次探测
{
    __int64 m, x, y;
    int i, j = 0;
    m = n - 1;
    while (!(m&1)) //计算(n-1)=m*(2^j)中的j和m,j=0时m=n-1,不断的除以2直至m为奇数
    {
        m = m >> 1;
        j++;
    }
    x = mod_exp(a, m, n);
    for (i = 1; i <= j; i++) {
        y = mod_mult(x, x, n);
        if ((y == 1) && (x != 1) && (x != n - 1)) //二次探测
            return true; //返回true时,n是合数
        x = y;
    }
    if (y != 1)
        return true;
    return false;
}
bool miller_rabin(int times, __int64 n) //对n进行times次的Miller测试
{
    __int64 a;
    int i;
    if (n == 2)
        return true;
    if (n<2||(n&1)==0)
        return false;
    for (i = 1; i <= times; i++) {
        a = rand() % (n - 2) + 2;
        if (Wintess(a, n))
            return false;
    }
    return true;
}
__int64 Pollard(__int64 n, __int64 c) //对n进行因字分解,找出n的一个因子,注意该因子不一定是最小的
{
    __int64 i, k, x, y, d;
    i = 1;
    k = 2;
    x = rand() % (n-1)+1;
    y = x;
    while (true) {
        i++;
        x = (mod_mult(x, x, n) + c) % n;
        d = gcd(n+y - x, n);
        if (d !=1 && d!=n)
            return d;
        if (y == x) //该数已经出现过,直接返回即可
            return n;
        if (i == k) {
            y = x;
            k = k << 1;
        }
    }
}
__int64 flag;
void get(__int64 n)
{
 if(n<=1||flag)return ;
 if(miller_rabin(TIME,n))
 {
  flag=n;
  return ;
 }
 __int64 t=Pollard(n,n-1);
 get(n/t);
 if(flag)return ;
 get(t);
}
int ant;
__int64 sum;
void find(__int64 m)
{
 __int64 i;
 __int64 tem;
 for(i=0;m>=prime[i]&&i<10;i++)
 {
  if(m%prime[i]==0){
   ant++;
   m/=prime[i];
   tem=prime[i];
   while(m%prime[i]==0){
    m/=prime[i];
    tem*=prime[i];
   }
   sum+=tem;
   flag=prime[i];
  }
 }
 while(m>1){
  flag=0;
  get(m);
  ant++;
  tem=1;
  while(m%flag==0){
   tem*=flag;
   m/=flag;
  }
  sum+=tem;
 }
}
int main()
{
 int cas;
 __int64 n;
 scanf("%d",&cas);
 while(cas--)
 {
  ant=0;
  sum=0;
  scanf("%I64d",&n);
      find(n);
  if(ant==1)sum/=flag;
  printf("%d %I64d\n",ant,sum);
 }
 return 0;
}


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值