zoukankan      html  css  js  c++  java
  • MR/PR学习笔记

    1 Miller-Rabin

    1.1 朴素筛法

    • 如何判断一个数是不是质数?
    • 如果 (2,3,cdots,lfloorsqrt n floor ot|~n),那么 (n) 就是质数。
    • 算法复杂度 (O(sqrt n)),有点慢。

    可惜,如果要保证答案正确,似乎并没有什么好方法了……

    等等,答案正确

    1.2 引入&铺垫

    • 没错,我们要使用不正确的算法过题了。

    1.2.1 为什么“不正确”的算法能过题

    • 如果你想在机房颓废,但是不知道老师在不在,你可以使用以下这个策略:
    1. 颓一分钟,有 (0.8) 的概率被老师发现。
    2. 重复第 (1)(10) 次。
    3. 如果都没被老师发现,就认为老师不在。

    这样的话,我们唯一的失误就是老师在,你颓废 (10) 次没被发现

    这个的概率是多少呢?(0.2^{10}=0.0000001024)。但是如果你只重复一次,失败的概率高达 (0.2)

    这说明了什么?

    我们只要用一个正确率相对高的方法随机采样判断,失误概率可以指数级下降。

    1.2.2 一些前置知识

    • 这些知识你可能小学就学过了,但是不要紧,我们来复习一下。下文中 (p) 都是素数。
    • 如果 ((a,p)=1)(a^{p-1}equiv1pmod p)
    • 如果 (x^2equiv1pmod p),则 (xequivpm1pmod p)

    我并不知道为什么很多人说第二个公式 (p) 必须是奇素数,(2) 应该也可以吧

    1.3 正片开始

    • 我们先钦定一个质数 (p)。你可以随便钦定,比如 (2)(3)(13),甚至是 (19260817)
    • Case 1:显然如果我们判断的数 (x=p),那么 (x) 是素数。
    • Case 2:显然如果 (p|x)(x>p),那么 (x) 是合数。
    • Case 3:显然如果 (p^{x-1} otequiv1pmod x),那么 (x) 是合数。
    • Case 4:以上三种都没有满足。
    1. 初始化 (k=x-1)
    2. 如果 (k) 是奇数,我们就认定 (x) 是素数(没错就这么草率)。
    3. (k=frac{k}{2},t=p^k\%x)
    4. 如果 (t otequivpm1pmod x),我们就知道 (x) 不是素数了。
    5. 如果 (tequiv-1pmod x),我们就认定 (x) 是素数(没错就这么草率)。
    6. 回到第一步。

    注意到在判断 (x) 不是素数的时候,我们是肯定的,但是在返回 (x) 是素数的时候,我用上了草率两字。不难举出很多判断是素数时的反例,然而大多数情况下,判断还是相对准确的。

    因此结合 1.2.1 中的内容,只要我们多判断几次,正确率就能接近百分之百了。

    注意到我们并没有限制 (p),所以 (p) 可以任意取正整数。由于题解中都这么写,我推荐大家使用 (2,3,5,7,11,13,19,61,2333,24251) 这十个数,听说它能顺利判断出所有 long long 范围的质数。

    1.4 实现

    1.4.1 小坑点

    由于模数 (x)long long 范围,两个模 (x) 意义下的非负整数相乘可能超出 long long 范围,由于 __int128 效率十分感人并且并不能在 NOI 系列比赛中使用,笔者采用龟速乘实现 (a imes b\%c)

    1.4.2 代码

    #include<bits/stdc++.h>
    #define int long long
    using namespace std;
    inline int read(){
       int s=0;
       char ch=getchar();
       while(ch<'0'||ch>'9') ch=getchar();
       while(ch>='0'&&ch<='9') s=s*10+(ch&15),ch=getchar();
       return s;
    }
    int mul(int x,int y,int p)
    {
    	int res=0;
    	for(int now=x; y; y>>=1,now<<=1,now%=p) (y&1)&&(res+=now,res%=p);
    	return res;
    }
    int qp(int x,int y,int p)
    {
    	int res=1;
    	for(int now=x; y; y>>=1,now=mul(now,now,p)) (y&1)&&(res=mul(res,now,p));
    	return res;
    }
    bool Miller_Rabin(int x,int p)
    {
    	for(int t,k=x-1; !(k&1);)
    	{
    		k>>=1,t=qp(p,k,x);
    		if(t!=1&&t!=x-1) return 0;
    		if(t==x-1) return 1;
    	}
    	return 1;
    }
    const int P[10]={2,3,5,7,11,13,19,61,2333,24251};
    bool is_prime(int x)
    {
    	for(int i=0; i<10; ++i) 
    	{
    		if(x==P[i]) return 1;
    		if(x%P[i]==0) return 0;
    		if(qp(P[i]%x,x-1,x)!=1) return 0;
    		if(!Miller_Rabin(x,P[i]%x)) return 0;
    	}
    	return 1;
    }
    signed main()
    {
        int n=read();
        if(is_prime(n)) puts("114514");
        else puts("1919810");
        return 0;
    }
    

    2 Pollard-Rho

    2.1 朴素筛法

    • 如何分解质因数?
    • 找出 (x) 的所有因子:对所有小于 (sqrt n) 的质数试除。
    • 算法复杂度 (O(sqrt n)),有点慢。

    可惜,如果要保证算法靠谱,似乎并没有什么好方法了……

    等等,算法靠谱

    2.2 跳过op

    小手一抖,op 没有,我们直入正题。

    2.2.1 从 MR 到 PR

    我们已经会高效判断 (x) 是不是质数了。

    如果我们要分解 (x),并且知道 (x) 不是质数,我们必然知道 (x) 有至少一个不超过 (sqrt x) 的质因子。

    如果我们已经找到了一个数 (t(t>1)) 使得 (t|x),我们就可以递归处理 (t)(frac{x}{t}) 了。但是 (t) 并不好找。

    这时,一个神仙出现了:找不到 (t),我们就找 (t) 的倍数,这样就增加了 (sqrt x) 倍的获奖概率!(为什么是 (sqrt x) 倍的中奖概率呢,因为必然存在一个 (t<sqrt x),而 (t) 的整数倍在 (x) 以内至少存在 (frac{x}{t}geqsqrt x) 个)

    如果我们每次尝试成功的概率是 (sqrt x)据说期望复杂度就是 ( ext O(n^frac{1}{4}))

    但是找到 (t) 的倍数又怎么转化回 (t) 呢……没错,就是 (gcd)

    因此我们只要随便选几个数 (gcd) 就行了。

    2.2.2 神奇的优化

    • 神奇的随机算法,floyd 判圈。
    • gcd 优化。
    • 一个我也看不懂的神奇优化,见讨论区。

    2.3 代码(被卡常)

    由于太逊就不给了。

    2.4 悲报

    我不懂为什么别人这么快啊……最后还是 system 过了这题/ll

  • 相关阅读:
    modelsim(2)
    【管理心得之十六】我来吐槽 “面试”
    【管理心得之十五】没有100%的答案,只有70%认可的答案
    【管理心得之十四】团队中的“短板”,是你?还是他?
    【管理心得之十三】真正步入轨道的管理,是单调无味的、是枯燥死板的
    【管理心得之十二】拿什么来拯救你我的“协力人员” (后篇)
    【管理心得之十一】拿什么来拯救你我的“协力人员” (前篇)
    【管理心得之十】你是信息的发送方,应尽的责任你做到了吗?
    【管理心得之九】奉劝那些把组织“玩弄于鼓掌之间”的OL们。(别让组织看见此篇)
    【管理心得之八】通过现象看本质,小王和小张谁更胜任?
  • 原文地址:https://www.cnblogs.com/dead-X/p/14274683.html
Copyright © 2011-2022 走看看