• prime


    素数判定算法,经典的Rabin Miller测试,通过二次探测的方法,可以将其正确率上升到一个很高的高度。

     

    $O(1)$的快速乘。

    在一些卡常数而且爆long long的取余问题中用到快速乘。

    朴素的快速乘是$O(logn)$的,从而添加了不必要的复杂度。

    爆long long的,实质上是取余的结果,在long long运算中只要不涉及除法,那么一直是对INF取余的结果,对答案没有干扰。

    1 LL mul(LL a,LL b,LL mod){
    2     if(a<=(LL)(1e8) && b<=(LL)(1e8)) return a*b%mod;
    3     return (a*b - (LL)(a/(LD)mod*b + 1e-3)*mod + mod) % mod;
    4 }

    注意快速乘在很小的数字时并不太稳,所以特判一下。

    注意一下Linux下rand()函数足够大,不需要拓充。

    转入正题:Rabin测试。

    我的Rabin在INT范围内不会出错,在LOGN LONG范围内出错的概率极低。

    首先是写一个check(LL x,LL P),用数字x检验P是否为素数。

     1 bool check(LL x,LL P){
     2     LL tmp=P-1;
     3     while(!(tmp&1)) tmp>>=1;
     4     LL m=qpow(x,tmp,P);
     5     if(m==1) return 1;
     6     while(tmp<P){
     7         if(m==P-1) return 1;
     8         tmp<<=1; m=mul(m,m,P);
     9     }
    10     return 0;
    11 }

    梳理一下过程

    首先将P-1中所有的2全都除掉。

    这时候如果tmp 为 P-1 或者 1是伪素数。(具体就用 $x^{tmp} = 1 (mod P)$判定)

    这时候检查$x^{2tmp} , x^{4tmp}, x^{8tmp} ....$是否等于 $P-1$。

    如果没有则说明P不是素数。

    接下来基于这一个$O(logn)$判定素数,我们有$O(n^{1/4})$的分解质因数算法。

    Rho算法。

    Rho算法是基于一个定理对于一个小于n的数字x如果 $(x,n) ≠ 1$ 则有,(x,n)为n的因子。

    这样考虑怎样高效地得到这样的数字x。

     1 LL Rdo(LL n,LL c){
     2     LL i=1,k=2,x,y,d,p;
     3     x=Rand()%n;
     4     y=x;
     5     while(1){
     6         i++;
     7         x=(mul(x,x,n)+c)%n;
     8         if(y==x) return n;
     9         p=Abs(x-y);
    10         d=gcd(p,n);
    11         if(d!=1&&d!=n) return d;
    12         if(i==k){
    13             y=x;
    14             k+=k;
    15         }
    16     }
    17 }
    18 
    19 int tot;
    20 LL a[N];
    21 
    22 void down(LL n){
    23     if(n==1) return;
    24     if(isprime(n)){
    25         a[++tot]=n;
    26         return;
    27     }
    28     LL t=n;
    29     while(t==n) t=Rdo(n,Rand()%(n-1)+1);
    30     down(t);
    31     down(n/t);
    32 }

    这样就可以得到了分解质因数的高效方法。

    注意一个数字的质因子最多有$O(logn)$个,因为质因数的乘积为n,而且质因数都大于1.

    注意在随机数据情况下,采用朴素分解质因数的效率也大概接近 $O(n^{frac{1}{4}})$,只不过会受到空间的限制。

    for(int i=1;prime[i]*(LL)prime[i]<=tmp;i++)
    {
        int cnt = 0;
        tim_cnt++;
        while(tmp % prime[i] == 0) tmp /= prime[i];
        ans *= (cnt+1);
    }

    注意是 <=tmp 而不是 <=n 

    给定一个整数N,求N最少可以拆成多少个完全平方数的和。 

    所以根据拉格朗日平方和定理,答案为1~4

    答案为1,开方验证

    答案为2,根据勾股数定理一个数字为勾股数当且仅当其质因数分解中所有的$4n+3$项的指数为偶数。

    答案为3,根据初等数论中的不等式 $n ≠ (8k + 7)  cdot 4^{m}$

    不然答案为4,根据 拉格朗日平方和定理即可。

  • 相关阅读:
    C# in Depth Third Edition 学习笔记-- Lambda表达式和表达式树
    几个比较实用的.Net 反编译工具
    使用Microsoft.Practices.EnterpriseLibrary.Data调用存数过程Output参数注意事项
    C# in Depth Third Edition 学习笔记-- C#2的一些特性
    C# in Depth Third Edition 学习笔记-- 可空类型
    C# in Depth Third Edition 学习笔记-- C#2.0: 解决C#1.0的问题 1 泛型
    C# in Depth Third Edition 学习笔记-- 值类型和引用
    .Net 程序员应该知道的工具和网站
    HTML 转 PDF
    C#、ASP.NET获取当前应用程序的绝对路径,获取程序工作路径 (转帖)
  • 原文地址:https://www.cnblogs.com/lawyer/p/4626147.html
Copyright © 2020-2023  润新知