数论初步
1.欧几里德算法
int gcd(int a,int b)
{
return b==0?a:gcd(b,a%b);
}
上面的算法即为欧几里德算法(Euclid algorithm),目的为求a与b的最大公约数。
gcd函数的递归成数不超过\(4.785\lg N+1.6723\),其中\(N=max\{a,b\}\)
利用gcd还可以求出两个整数a,b的最小公倍数lcm(a,b),可以用唯一分解定理证明,不难得到gcd(a,b)*lcm(a,b)=a*b,如果把lcm写成a*b/gcd(a,b),a*b可能会溢出,正确写法是a/gcd(a,b)*b
int lcm(a,b)
{
return a/gcd(a,b)*b;
}
2.Eratosthenes 筛法
int m=sqrt(n+0.5);
memset(vis,0,sizeof(vis));
for(int i=2;i<=m;i++)
if(!vis[i])
for(int j=i*i;j<=n;j+=i)
vis[j]=1;
对于不超过n的每个非负整数p,删除2p,3p,4p,…,当处理完所有数之后,还没有被删除的就是素数。上述代码中vis[i]表示i已被删除
内层循环不用从i*2开始——它已经在i=2时被筛掉了
3.扩展欧几里德算法
void gcd(int a,int b,int& d,int& x,int& y)
{
if(!b)
{
d=a;
x=1;
y=0;
}
else
{
gcd(b,a%b,d,y,x);
y-=x*(a/b);
}
}
找出一对整数(x,y),使得\(ax+by=gcd(a,b)\),这里的x,y不一定是整数,也可能是负数或0。
如果要找多对则整数呢?
设gcd(a,b)=g,任取另外一组解(x2,y2),则ax1+by1=ax2+by2,变形得a(x1-x2)=b(y2-y1),左右两边同时除以g,得a'(x1-x2)=b'(y2-y1),其中a’=a/g,b'=b/g。此时a’和b'互素,因此x1-x2一定是b'得整数倍,设x1-x2为kb',经计算得y2-y1=ka',所以得到如下结论
设a,b,c为任意整数。若方程
ax+by=c得一组整数解为(x0,y0),则它的任意整数解都可以写成(x0+kb',y0-ka'),其中a'=a/gcd(a,b),b'=b/gcd(a,b),k取任意整数。
4.同余与模算术
\((a+b)mod\ n=((a\ mod\ n)+(b\ mod\ n))mod\ n\)
\((a-b)mod\ n=((a\ mod\ n)-(b\ mod\ n)+n)mod\ n\)
\(ab\ mod\ n=(a\ mod\ n)(b\ mod\ n)mod\ n\)
\(a\equiv b(mod\ n )\)的含义是“a和b除以n的余数相同”,其充要条件是“a-b是n的整数倍”。
大整数取模:输入正整数n和m,输出n mod m的值。\(n\leq10^{100},m\leq10^9\)
scanf("%s%d",n,&m);
int len=strlen(n);
int ans=0;
for(int i=0;i<len;i++)
ans=(int)(((long long)ans*10+n[i]-'0')%m);
printf("%d\n",ans);
幂取模:输入正整数a,n和m,输出\(a^n\ mod\ m\)的值。\(a,n,m\leq 10^9\)
int pow_mod(int a,int n,int m)
{
if(n==0)
return 1;
int x=pow_mod(a,n/2,m);
long long ans=(long long)x*x%m;
if(n%2==1)
ans=ans*a%m;
return (int)ans;
}

浙公网安备 33010602011771号