一.素数打表:
1.平常打表:
for(i=2;i<=n;i++)
if(!s[i])
{
for(j=2*i;j<=n;j+=i)
s[j]=1;
} 2.线性打表:
void get_prime()
{
int cnt = 0;
for (int i = 2; i < N; i++)
{
if (!tag[i])
p[cnt++] = i;
for (int j = 0; j < cnt && p[j] * i < N; j++)
{
tag[i*p[j]] = 1;
if (i % p[j] == 0)
break;
}
}
}
1.欧几里得:
int gcd(int a,int b)
{
return b==0?a:gcd(b,a%b);
}//求整数x和y,使得ax+by=d,且|x|+|y|最小。其中d=gcd(a,b)
void extend_gcd(int a,int b,int &d,ll &x,ll &y)
{
if(!b) d=a,x=1,y=0;
else {extend_gcd(b,a%b,d,y,x);y-=x*(a/b);}
}//求a^b%n
ll mod(ll a,ll b,int n)
{
if(b==0) return 1;
ll ans=mod(a,b/2,n);
ans=ans*ans%n;
if(b&1) ans=ans*a%n;
return ans;
}欧拉函数phi(n)等于不超过n且和n互素的整数个数。 互素:两个数的最大公约数为1的数称为互素数。
1.单个欧拉函数求法代码:
int euler_phi(int n)
{
int m=sqrt(n+0.5),ans=n;
for(int i=2;i<=m;i++)
if(n%i==0)
{
ans=ans/i*(i-1);
while(n%i==0) n/=i;
}
if(n>1) ans=ans/n*(n-1);
return ans;
}2.函数表:多个欧拉函数一起求,类似筛选法计算phi(1),phi(2),……phi(n).
int phi[MM]
void phi_table(int n)
{
mem(phi,0); phi[1]=1;
for(int i=2;i<=n;i++)
if(!phi[i])
for(int j=i;j<=n;j+=i)
{
if(!phi[j]) phi[j]=j;
phi[j]=phi[j]/i*(i-1);
}
}五.乘法逆:
在n的同余类中的两个数a和b满足ab=1,比如在15的同余类中7*13=1,在这种情况下,说a和b互为乘法的逆。即7的逆的13,13的逆为7;如果知道a就可以求b,知道b也就可以求a。代码如下:
1.用扩展欧几里得求:
//计算模n下a的逆。如果不存在逆,返回-1
int inv(int a,int n)
{
int d,x,y;
extend_gcd(a,n,d,x,y); //扩展欧几里得函数
return d==1?(x+n)%n:-1;
}
2.利用欧拉定理求:
//a的逆就是mod(a,n-2,n)
ll mod(ll a,ll n-2,int n)
{
if(b==0) return 1;
ll ans=mod(a,b/2,n);
ans=ans*ans%n;
if(b&1) ans=ans*a%n;
return ans;
}
1.线性模方程:axob(mod n)
//返回0时不存在解,为1有解
int mod_gcd(int a,int b,int n)
{
int x,y,d,x0,i;
extend_gcd(a,n,d,x,y);
if(b%d) return 0;
x0=x*(b/d)%n;
for(i=1;i<d;i++)
printf("%d\n",(x0+i*(n/d))%n);
return 1;
}2.费马小定理:a^(p-1) ≡1(mod p)
费马小定理是数论中的一个重要定理,其内容为: 假如p是质数,且(a,p)=1,那么 a^(p-1) ≡1(mod p)。
即:假如p是质数,且a,p互质,那么a的(p-1)次方除以p的余数恒等于1。
3.中国剩余定理:xoai(mod mi)
如果线性模方程有多个,xoai(mod mi)该怎么做呢?这里就可以用中国剩余定理了。令M为所有mi的乘积,则在模M的剩余系下原方程组有唯一解。
//n个方程:x=a[i](mod m[i]) (0<=i<n)
ll china(int n,int *a,int *m)
{
ll M=1,d,y,x=0;
for(int i=0;i<n;i++)
M*=m[i];
for(int i=0;i<n;i++)
{
ll w=M/m[i];
gcd(m[i],w,d,d,y);
x=(x+y*w*a[i])%M;
}
return (x+M)%M;
}利用欧拉定理求解模方程,当n为素数时,解模方程a^xob(mod n)。根据欧拉定理,只需检查x=0,1,2,……,n-1是不是解即可因为a^(n-1)o1(mod n),当x超过n-1时a^x就开始循环了。
//求解模方程a^xb(mod n)。n为素数。无解返回0
int log_mod(int a,int b,int n)
{
int m,v,e=1,i;
m=sqrt(n+0.5);
v=inv(mod(a,m,n),n);
map<int,int>x;
x[1]=0;
for(i=1;i<m;i++)
{
e=e*a%n;
if(!x.count(e)) x[e]=i;
}
for(i=0;i<m;i++)
{
if(x.count(b)) return i*m+x[b];
b=b*v%n;
}
return 0;
}原文:http://blog.csdn.net/u011466175/article/details/20218021