数论概览——素数篇

很久没写数论了,现在筛个素数都吃力了,写几道老题熟练一下,顺便弄下今年的模板

第一部分:关于素数

素数是数论里最重要的一种数,很多定理和性质都由素数展开。所以就有人称数论为素论,可见素数在数论中的重要性。

1.筛素数 记一下素数定理:小于N的素数的个数为f(N) 则f(N)~N/lnN,N->正无穷
【线性筛素数】【区间筛素数】
[POJ2689]http://poj.org/problem?id=2689
/*
计算L,U区间内相邻的差最小的和差最大的两对素数
L,U可能很大,但U-L不大,二次筛素数即可,区间筛素数
*/
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
typedef long long intt;
const int MAXN2 = 1000100;
const int MAXN = 47000;
int noprime[MAXN],pcnt,p[MAXN];
inline void getprime(){
        pcnt = 0;
        memset(noprime,0,sizeof(noprime));
        noprime[0] = noprime[1] = 1;
        for(int i = 2; i < MAXN; ++i){
                if(!noprime[i])p[pcnt++] = i;
                for(int j = 0; j < pcnt && i*p[j] < MAXN; ++j){
                        noprime[i*p[j]] = 1;
                        if(i%p[j] == 0)break;
                }
        }
}

intt p2[MAXN2];
int pcnt2,noprime2[MAXN2];
inline void getprime2(intt L,intt U){
        pcnt2 = 0;
        if(U < MAXN){
                int s = 0;
                while (p[s] < L)s++;
                for(intt i = s; p[i] <= U; ++i)p2[pcnt2++] = p[i];
                return;
        }
        for(int i = 0; i <= U-L; ++i)noprime2[i] = 0;
        
        for(int i = 0; i < pcnt && p[i]*p[i] <= U; ++i){
                intt st = L/p[i];
                if(L%p[i] == 0)st = L;
                else st = p[i]*(st+1);    
                for(intt j = st; j <= U; j += p[i])
                    noprime2[j-L] = 1;
        }
        if(L == 1)noprime2[0] = 1;
        for(intt i = L; i <= U; ++i){
                if(!noprime2[i-L])p2[pcnt2++] = i;
        }
}
int main(){
        intt L,U;
        getprime();
        while (scanf("%lld%lld",&L,&U) != EOF){
                getprime2(L,U);
                if(pcnt2 < 2){
                        puts("There are no adjacent primes.");
                        continue;
                }
                intt ansmax = 0,ima = 0;
                intt ansmin = U,imi = 0;
                
                for(int i = 1; i < pcnt2; ++i){
                        if(ansmax < p2[i] - p2[i-1]){
                                ansmax = p2[i] - p2[i-1];
                                ima = i;
                        }
                        if(ansmin > p2[i] - p2[i-1]){
                                ansmin = p2[i] - p2[i-1];
                                imi = i;
                        }
                }
                printf("%lld,%lld are closest, %lld,%lld are most distant.\n",p2[imi-1],p2[imi],p2[ima-1],p2[ima]);
        }
        return 0;
}


【质因子分解】【n!的质因子分解】
[POJ2649]http://poj.org/problem?id=2649
/*
*两个数n和m,问n!能否整除m
*先对m质因数分解,然后判断n!的m中的质因子的数目是不是大于m中该质因子的个数
*这里有个结论:n!中因子p的个数可以这样求:
*int t = n,sum = 0;
*while ( t > 0 ) {
*     sum += t / p;
*     t /= p;
*}
*sum即为n!中因子p的个数
*/
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;

const int MAXN = 65537;

int noprime[MAXN],pcnt,p[MAXN/2];
inline void getprime(){
        pcnt = 0;
        memset(noprime,0,sizeof(noprime));
        noprime[0] = noprime[1] = 1;
        for(int i = 2; i < MAXN; ++i){
                if(!noprime[i])p[pcnt++] = i;
                for(int j = 0; j < pcnt && i*p[j] < MAXN; ++j){
                        noprime[i*p[j]] = 1;
                        if(i%p[j] == 0)break;
                }
        }
}

int nump[MAXN/2],yinzi[MAXN/2];
int n,m,top;
inline void cal(int t){
        memset(nump,0,sizeof(nump));
        top = -1;
        int tmp = t;
        for(int i = 0;i < pcnt && p[i] <= tmp; ++i){
                if(t % p[i] == 0){
                    yinzi[++top] = p[i];
                    while (t % p[i] == 0){
                            nump[top] ++;
                            t /= p[i];
                    }
                }
                if(t == 1)break;
        }
        if(t > 1){
                yinzi[++top] = t;
                nump[top] ++;
        }

}

int main(){
        getprime();
        while (scanf("%d%d",&n,&m) != EOF){
                if(m == 0){
                        printf("%d does not divide %d!\n", m, n);
                           continue;
                }
                cal(m);
                bool ok = 1;
                for(int i = 0; i <= top; ++i){
                        if(yinzi[i] > n){
                                ok = 0;
                                break;
                        }
                        int t = n,sum = 0;
                        while (t > 0){
                                sum += t/yinzi[i];
                                t /= yinzi[i];
                                if(sum >= nump[i])break;
                        }
                        if(sum < nump[i]){
                                ok = 0;
                                break;
                        }
                }
                if(ok)printf("%d divides %d!\n",m,n);
                else printf("%d does not divide %d!\n",m,n);
        }
        return 0;
}


/*
质因子分解的用途
对求数字的因子加速,即任何的n的素因子Pi都有Pi|n,这是显然的.于是可以利用这个特点,在得到素因子的种类和个数以后采取枚举的做法来得到所有的因子(一般用dfs递归实现)
*/
2.素数测试
【米勒拉宾素数测试+RHO大数分解】
a)最简单的是(2..sqrt(n))试除判断是否素数 复杂度O(sqrt(N))
b)米勒拉宾素数测试+RHO大数分解 复杂度O(logN)
Miller - Rabin素数测试的伪码
Input: n > 2, an odd integer to be tested for primality; k, a parameter that determines the accuracy of the test  
Output: composite if n is composite, otherwise probably prime  
write n − 1 as 2^s·d with d odd by factoring powers of 2 from n − 1  
LOOP: repeat k times:  
    pick a randomly in the range [2, n − 2]  
    x ← a^d mod n  
    if x = 1 or x = n − 1 then do next LOOP  
    for r = 1 .. s − 1  
       x ← x^2 mod n  
       if x = 1 then return composite  
       if x = n − 1 then do next LOOP  
    return composite  
return probably prime 

[POJ1811]模板题,直接上代码
#include <cstdio>
#include <cstring>
#include <ctime>
#include <algorithm>
using namespace std;
typedef long long bint;
const int TIME = 8;//测试次数,8~10够了
int factor[100],fac_top = -1;

//计算两个数的gcd
inline bint gcd(bint small,bint big){

        while(small){
                swap(small,big);
                small%=big;
        }
        return big > 0 ? big : -big;
}

//ret = (a*b)%n (n<2^62)
inline bint muti_mod(bint a,bint b,bint n){
        bint exp = a%n, res = 0;
        while(b){
                if(b&1){
                        res += exp;
                        if(res>n) res -= n;
                }
                exp <<= 1;
                if(exp>n) exp -= n;

                b>>=1;
        }
        return res;
}

// ret = (a^b)%n
inline bint mod_exp(bint a,bint p,bint m){
        bint exp=a%m, res=1; //  
        while(p>1)
        {
                if(p&1)//
                        res=muti_mod(res,exp,m);
                exp = muti_mod(exp,exp,m);
                p>>=1;
        }
        return muti_mod(res,exp,m);
}

//miller-rabin法测试素数, time 测试次数O(lonN)
inline bool miller_rabin(bint n, int times){
        if(n==2)return 1;
        if(n<2||!(n&1))return 0;

        bint a, u=n-1, x, y;
        int t=0;
        while(u%2==0){
                t++;
                u/=2;
        }

        srand(time(0));
        for(int i=0;i<times;i++){
                a = rand() % (n-1) + 1;
                x = mod_exp(a, u, n);
                for(int j=0;j<t;j++){
                        y = muti_mod(x, x, n);
                        if ( y == 1 && x != 1 && x != n-1 )
                                return false; //must not
                        x = y;
                }
                if( y!=1) return false;
        }
        return true;
}


inline bint pollard_rho(bint n,int c){//找出一个因子
        bint x,y,d,i = 1,k = 2;
        srand(time(0));

        x = rand()%(n-1)+1;
        y = x;
        while(true) {
                i++;
                x = (muti_mod(x,x,n) + c) % n;
                d = gcd(y-x, n);
                if(1 < d && d < n)return d;
                if( y == x)       return n;
                if(i == k) {
                        y = x;
                        k <<= 1;
                }
        }
}

inline void findFactor(bint n,int k){//二分找出所有质因子,存入factor,
        if(n==1)return;

        if(miller_rabin(n, TIME)){
                factor[++fac_top] = n;
                return;
        }
        bint p = n;
        while(p >= n)
                p = pollard_rho(p,k--);//k值变化,防止死循环
        findFactor(p,k);
        findFactor(n/p,k);
}

int main(){
        bint cas,n,min;
        scanf("%lld",&cas);
        while(cas--){
                scanf("%lld",&n);
                fac_top = min = -1;
                if(miller_rabin(n,TIME)) puts("Prime");
                else{
                        findFactor(n,1000);
                        //factor保存该数的所有质因子,0..fac_top
                        for(int i = 0;i <= fac_top;i++){
                                if(min < 0 || factor[i] < min)
                                        min = factor[i];
                        }
                        printf("%lld\n",min);
                }
        }

        return 0;
}


3.欧拉函数
对正整数n,欧拉函数是少于或等于n的数中与n互质的数的数目
显然对素数n,phi(n)=n-1
通式:φ(x)=x(1-1/p1)(1-1/p2)(1-1/p3)(1-1/p4)…..(1-1/pn),其中p1, p2……pn为x的所有质因数,x是不为0的整数。φ(1)=1(唯一和1互质的数就是1本身)
很简单,就不写代码什么的了
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值