开头大佬博客祭天%%%%
整除
规定,如果,数a%b==0 ,那么称a可以整除b。整除符号为“|”。
记做:a|b
取余的几个公式
快速幂
求一个数a的b次方.
设b=6,
那么,a6可以分解为a2+4=a2*a4,即将6转化为2进制110,遇到1就乘一下即可
typedef long long ll;
ll quick_power(ll a, ll b)
{
ll ans = 1;
for (; b; b >>= 1, a *= a)
if (b & 1)
ans *= a;
return ans;
}
欧几里得求余
辗转相除法的计算过程可以用图形演示。假设我们要在a×b的矩形地面上铺正方形瓷砖,并且正好铺满,其中a大于b。我们先尝试用b×b的瓷砖,但是留下了r_0×b的部分,其中r_0<b。我们接着尝试用r_0×r_0的正方形瓷砖铺,又留下了r_1×r_0的部分,然后再使用r_1×r_1的正方形铺……直到全部铺满为止,即到某步时正方形刚好覆盖剩余的面积为止。此时用到的最小的正方形的边长就是原来矩形的两条边长的最大公约数。在图中,最小的正方形面积是21×21(红色),而原先的矩形(绿色)边长是1071×462,所以21是1071和462的最大公约数。
int gcd(int a, int b)
{
int r = 1;
while (r)
r = a % b,a = b,b = r;
return a;
}
或
int gcd(int a,int b)
2 {
3 return b ? gcd(b,a%b) : a;
4 }
扩展欧几里得
基本算法:对于不完全为 0 的非负整数 a,b,gcd(a,b)表示 a,b 的最大公约数,必然存在整数对 x,y ,使得 gcd(a,b)=ax+by
证明:设 a>b
1.显然当 b=0,gcd(a,b)=a。此时 x=1,y=0;
2.ab!=0 时
设 ax1+by1=gcd(a,b);
bx2+(a mod b)y2=gcd(b,a mod b);
根据朴素的欧几里德原理有 gcd(a,b)=gcd(b,a mod b);
则:ax1+by1=bx2+(a mod b)y2;
即:ax1+by1=bx2+(a-(a/b)*b)y2=ay2+bx2-(a/b)*by2;
根据恒等定理得:x1=y2; y1=x2-(a/b)*y2;
这样我们就得到了求解 x1,y1 的方法:x1,y1 的值基于 x2,y2.
上面的思想是以递归定义的,因为 gcd 不断的递归求解一定会有个时候 b=0,所以递归可以结束。
有两个数a,b,对它们进行辗转相除法,可得它们的最大公约数——这是众所周知的。然后,收集辗转相除法中产生的式子,倒回去,可以得到ax+by=gcd(a,b)的整数解。
扩展欧几里得算法可以用来计算模反元素(也叫模逆元),而模反元素在RSA加密算法中有举足轻重的地位。
int exgcd(int a,int b,int &x,int &y)
{
if(b==0){
x=1,y=0;
return a;
}
int r=exgcd(b,a%b,x,y),t=x;
x=y,y=t-a/b*y;
return r;
}
E筛
让我们用手来模拟一下,在2时,划去4,6,8,10,14,16,3划去6,9,15,在5划去10,在7划去14,在11和13不划。于是得到了下图的素数表。
int visit[MAX]={1,1};
void Prime(int n)
{
for(int i=2;i<=n;i++)
if(!visit[i])
for(int j=i+i;j<=n;j+=i)
visit[j]=1;
}
欧拉筛
由上图很明显我们可以看出,这个埃筛重复了好多遍去筛一个数。欧拉筛便是改进。
令每一个数只让它最小的素数因子筛去。
int visit[MAX],prime[MAX];
void Prime(int n)
{
for (int i = 2;i <= n; i++) {
if (!visit[i])
prime[cnt] = i,cnt++;
for (int j = 0; j <cnt && i*prime[j] <= n; j++) {
visit[i*prime[j]] = 1;
if (i % prime[j] == 0)
break;
}
}
}