ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Fansblog(Miller_Rabin, 费马小定理, 逆元, 威尔逊定理)

2021-02-17 17:57:42  阅读:181  来源: 互联网

标签:return Miller 定理 Fansblog ret res ll mod


题面

给你一个素数p,让你求 k!%p, 其中k为比p小的整数里最大的素数。例如p=5,则k=3。p=11,则k=7。 k! = k*(k-1)*······21;
Input
第一行包含一个整数 T(1<=T<=10) 表示测试样例的个数.
接下来有T行,每行包含一个素数 p (1e9≤p≤1e14)
Output
对于每个测试样例,输出一个整数k!%p,代表答案
Sample Input
1
1000000007
Sample Output
328400734

思路: 威尔逊定理 (p - 1) ! % p = p - 1
显然 k! * (k + 1) ~ * (p - 1) % p = p - 1 % p
k! % p = 1/((k + 1) ~*(p - 1)) %p
我们只需找到1/(k + 1) , ~ 1 / (p - 1) 的逆元
由费马小定理可得
x^(p - 1) % p = 1 % p;
x * x^(p - 2) % p = 1 % p;
则 x和x^(p - 2)互为乘法逆元
eg a * b % p = a * b * b ^ (p - 1) % p = a * b ^ p % p
a * b ^(-1) % p = a * b ^(-1) * b ^(p - 1) % p = a * b ^ (p - 2) % p
Miller_Rabin
对于一个大数我们可以用两种方法来判断是否为质数
取随机数 n 来判断 p 是否为质数
1, 费马小定理
如果p为质数则 至少满足 n^(p - 1) % p = 1 % p;
如果不满足则p一定不是质数,满足则可能是质数。
但正确率可能较低所以要二次探测
2.二次检测定理
如果p是一个素数,则x^2%p==1的解为,则x=1或者x=p-1。
证明: x ^ 2 - 1 % p == 0
(x - 1) *(x + 1) %p == 0
则 x == 1 || x == p - 1

更多细节见于代码

#include <bits/stdc++.h>

using namespace std;
#define ll long long
const long long S = 20; // 探测次数
ll ksj(ll a,ll b,ll mod)//快速乘
{
	ll res=0;
	while(b)
  {
		if(b & 1) res = (res + a) % mod;
		a = (a + a) % mod;
		b >>= 1;
	}
	return res;
}
ll ksm(ll a,ll b,ll mod)//快速幂
{
	ll res=1;
	a %= mod;
	while(b)
  {
		if(b&1) res = ksj(res, a, mod);
		a = ksj(a, a, mod);
    b >>= 1;
	}
	return res;
}
int check(ll a, ll n, ll x, ll t){
    ll ret = ksm(a, x, n);//费马小定理 a^(p-1)%p==1
    ll last = ret;
    for(ll i = 1; i <= t; i++)
    {//二次检测定理 如果p是一个素数,则x^2%p==1的解为,则x=1或者x=n-1。
        ret = ksj(ret, ret, n);
        if(ret == 1 && last != 1 && last != n-1) return 1;
        last=ret;
    }
    if(ret != 1) return 1;
    return 0;
}
int Miller_Rabin(ll n){
    if(n < 2)return 0;
    if(n == 2)return 1;
    if((n&1) == 0) return 0;
    ll x = n - 1;
    ll t = 0;
    while((x&1) == 0){ x >>= 1; t++;}
    for(ll i = 0; i < S; i++){
        ll a = rand() % (n-1) + 1;
        if(check(a, n, x, t))  return 0;
    }
    return 1;
}

int main()
{
    int t;
    scanf("%d", &t);
    while(t --)
    {
        ll p, n, q;
        scanf("%lld", &n);
        p = n - 1;
        while(!Miller_Rabin(p)) p --;
        ll ans = 1;
        for(ll i = p + 1; i < n - 1; i++)
        {
            ans = ksj(ans, ksm(i, n - 2, n), n);
        }
        printf("%lld\n", ans);
    }
    return 0;
}

标签:return,Miller,定理,Fansblog,ret,res,ll,mod
来源: https://blog.csdn.net/qq_45778406/article/details/113835733

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有