素数筛选
求所有小于n的素数
#include<bits/stdc++.h>
using namespace std;
const int N=1000;
int prim[N];
int n;
int main()
{
while(cin>>n)
{
//初始化2到n都是素数
for(int i=2;i<=n;i++)
{
prim[i]=1;
}
//从2到n把所有的是当前数的倍数的数都设置为0
//不能设置自己为0
for(int i=2;i<=n;i++)
{
for(int j=2;j<=n;j++)
{
if(j%i==0&&i!=j)
{
prim[j]=0;
}
}
}
for(int i=2;i<=n;i++)
{
if(prim[i])
{
cout<<i<<" ";
}
}
}
}
扩展欧几里得算法
gcd=gcd(a,b);
那么存在gcd=ax+by;扩展欧几里得算法要求求出gcd,并且可以求出所有xy的解;
根据欧几里得算法我们知道gcd(a,b)=gcd(b,a%b)
那么就有b*x1+(a%b)*x2=gcd
又a%b=a-(a/b)*b;
将a%b进行替换,得到
gcd=a*y1+b*(x1-a/b*y1)
进而可以写出递归方程:
现在考虑递归终止
因为欧几里得算法就是在b=0的时候返回a,扩展欧几里得算法的最终状态就是
a*1+b*0=gcd;//不断递归达到的状态,然后反向递归求出xy,x就是a关于m的逆元
#include<bits/stdc++.h>
using namespace std;
const int N=1000;
int egcd(int a,int b,int &x,int &y)//xy都是可修改的
{
if(b==0)
{
x=1;
y=0;
return a;
}
else
{
int ans=egcd(b,a%b,x,y);
//注意这里更新xy的操作的位置,
//因为ab的值是由上一层得到的,所以在参数里面就改了
//而xy的值是在下一层得到的,所以在递归调用之后更新。
int t=x;
x=y;
y=t-a/b*y;
returna ans;
}
//根据扩展欧几里得:这一层的xy可以由下一层的得到
}
扩展欧几里得算法来求乘法逆元:
给出一个式子 ax ≡ 1 (mod m) 这个式子等价于 ax+my=1;
扩展欧几里得中有:
上面那个式子的解是:x=x0+(m/1)*t y=y0+(a/1)*t
这样可以得知所有符合条件的x的解都是关于m同余的;
此时x是a关于m的乘法逆元,那么我们可以得到一定存在一个最小的解,而且这个解是小于m的;
总的来说扩展偶欧几里得算法就是求一个方程的解。
通过不断递归求出a*1+b*0=1这个状态,然后反向递归求出x,即为a关于m的乘法逆元
#include<bits/stdc++.h>
using namespace std;
const int N=1000;
int a,b,x,y;
int egcd(int a,int b,int &x,int &y)
{
if(b==0)
{
x=1;
y=0;
return a;
}
else
{
int ans=egcd(b,a%b,x,y);
//注意这里更新xy的操作的位置,
//因为ab的值是由上一层得到的,所以在参数里面就改了
//而xy的值是在下一层得到的,所以在递归调用之后更新。
int t=x;
x=y;
y=t-a/b*y;
return ans;
}
//根据扩展欧几里得:这一层的xy可以由下一层的得到
}
int main()
{
cin>>a>>b;
cout<<(egcd(a,b,x,y)==1?(x%b+b)%b:-1)<<endl;
//x可能超过b了,所以取模,取模之后可能会是负数,所以加上b,然后再取模,保证范围
return 0;
}