1.快速幂,利用幂运算的性质,快速计算一个数的n次方(mod m)
int quickpow(int a,int b,int c)
{
int ans=1;a=a%c;
while(b>0)
{if(b%2==1)ans=(ans*a)%c;
b=b/2;a=a*a%c;}return ans;
}
模板题:
#include<iostream>
#include<cstdlib>
#include<cstdio>
using namespace std;
int b,p,k;
int quickpow(int,int,int);
int main()
{
cin>>b>>p>>k;
cout<<b<<"^"<<p<<" mod "<<k<<"="<<quickpow(b,p,k);
return 0;
}
int quickpow(int a,int b,int c)
{
int ans=1;a=a%c;
while(b>0)
{if(b%2==1)ans=(ans*a)%c;
b=b/2;a=a*a%c;}return ans;
}
2.快速乘
发现如果要算两个1e18数相乘再mod一个1e18的数如ab%p,如果直接相乘,很容易发现有可能直接爆long long的范围,解决方法也很好想出来,就是利用类似快速幂的方法,把两个乘数的因子分解出来,一个一个乘,再利用模运算的性质将范围控制在long long 的范围内,那么时间复杂度就是logn这样就有可能被卡时,那么此时就可以用long double的性质(保留18位舍弃低位)先保存ab/p的除数,最后的取模后的结果就是ab再减掉刚刚除数p
快速乘板子:
inline long long multi(long long x,long long y,long long mod)
{
long long tmp=(x*y-(long long)((long double)x/mod*y+1.0e-8)*mod);
return tmp<0 ? tmp+mod : tmp;
}
---------------------
代码来源
作者:Coder_YX
原文:https://blog.csdn.net/qq_34731703/article/details/66478286
--------------------
3.费马小定理
如果p是质数并且gcd(a,p)=1那么有a的p-1次方在mod p时和1同余
奇淫巧技:米勒罗宾测试
如果p是质数那么上述公式成立,反过来,这个式子成立p不一定成立。但是如果这个式子不成立这个p一定是和数,那么就会给我们提供一种快速检测一个数的素性的方法,先随机一个a带入费马小定理,如果不成立,那么一定是和数,如果成立,他有1/2的概率是质数,当他通过了足够多的测试之后,我们有足够的把握确定这个数是一个质数。
ps:有几个和数可以通过米勒罗宾测试,但是概率极小
代码:
bool check(long long a,long long n,long long x,long long t)
{
long long ret=quickpow(a,x,n);
long long last=ret;
for(int i=1;i<=t;i++)
{
ret=quickmu(ret,ret,n);
if(ret==1&&last!=1&&last!=n-1) return 1;
last=ret;
}
if(ret!=1) return 1;
return 0;
}
bool Robin_Miller(long long n)
{
if(n<2)return 0;
if(n==2)return 1;
if((n&1)==0) return 0;
long long x=n-1;
long long t=0;
while((x&1)==0){x>>=1;t++;}
for(int i=0;i<S;i++)
{
long long a=rand()%(n-1)+1;
if(check(a,n,x,t))
return false;
}
return true;
}