P4714 「数学」约数个数和

题解:

会了Miller-Rabin这题就很简单了

首先这种题很容易想到质因数分解

但是暴力根号算法是不行的

所以要用到

Miller-Rabin素数

https://blog.csdn.net/ltyqljhwcm/article/details/53045840

对于要判断的数n

1.先判断是不是2,是的话就返回true。

2.判断是不是小于2的,或合数,是的话就返回false。

3.令n-1=u*2^t,求出u,t,其中u是奇数。

4.随机取一个a,且1<a<n

/*根据费马小定理,如果a^(n-1)≡1(mod p)那么n就极有可能是素数,如果等式不成立,那肯定不是素数了

因为n-1=u*2^t,所以a^(n-1)=a^(u*2^t)=(a^u)^(2^t)。*/

5.所以我们令x=(a^u)%n

6.然后是t次循环,每次循环都让y=(x*x)%n,x=y,这样t次循环之后x=a^(u*2^t)=a^(n-1)了

7.因为循环的时候y=(x*x)%n,且x肯定是小于n的,正好可以用二次探测定理,

如果(x^2)%n==1,也就是y等于1的时候,假如n是素数,那么x==1||x==n-1,如果x!=1&&x!=n-1,那么n肯定不是素数了,返回false。

8.运行到这里的时候x=a^(n-1),根据费马小定理,x!=1的话,肯定不是素数了,返回false

9.因为Miller-Rabin得到的结果的正确率为 75%,所以要多次循环步骤4~8来提高正确率

10.循环多次之后还没返回,那么n肯定是素数了,返回true

#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int kk=10;
ll n;
ll C(ll x,ll y)
{
  if (y==1) return(x);
  if (y%2==1) return(((C(x,y/2)*2)%n+x)%n);
  else return((C(x,y/2)*2)%n);
}
ll M(ll x,ll y)
{
  if (y==1) return(x);
  ll tmp=M(x,y/2);
  if (y%2==1) return(C(C(tmp,tmp),x));
  else return(C(tmp,tmp));
}
bool pd()
{
  if (n==2) return 1;
  if (n<2) return 0;
  ll m=n-1;
  int k=0;
  while (!(m&1))
  {
    k++; m>>=1;
  }
  for (int i=1;i<=kk;i++)
  {
    ll x1=rand()%(n-1)+1;
    ll x2=M(x1,m);
    ll y=0;
    for (int j=1;j<=k;j++)
    {
      y=C(x2,x2);
      if (y==1&&x2!=1&&x2!=n-1) return 0;
      x2=y;
    }
    if (y!=1) return 0;
  }
  return 1;
}
int main()
{
 // freopen("1.in","r",stdin);
 // freopen("1.out","w",stdout);
  while (cin>>n)
  {
    
    if (pd()) cout<<"T"; else cout<<"F";
    cout<<endl;
  }
  return 0;
}

Pollard-rho算法:

原文地址:https://www.cnblogs.com/yinwuxiao/p/9251974.html