一、模运算性质
- ( a + b ) % m = ( ( a % m ) + ( b % m ) ) % m;
- ( a - b ) % m = ( ( a % m ) - ( b % m ) ) % m;
- ( a * b ) % m = ( ( a % m ) * ( b % m ) ) % m;
二、快速幂
1、普通快速幂
核心思想:a^n = a^(x1+x2+x3+x4+......+xn) = a^x1 * a^x2 * a^x3 * ...... * a^xn;
快速的理解就是:x1,x2,x3,x4是倍数的增长,能达到少循环的效果。
引入二进制能更好判断什么时候乘a的幂;
例如:a^11=a^(1+2+8),他是如何出来的呢???11的二进制1011==1*(2^3)+0*(2^2)+(1*2^1)+(1*2^0);这样就可以进行加乘了。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
LL fastPow(LL a,LL n)
{
LL base=a; //作用是a的多少次幂
LL res=1;
while(n)
{
if(n&1) //判断是否要乘
res*=base;
base*=base; //更新n的数
n>>=1; //右移
}
return res;
}
int main()
{
ios::sync_with_stdio(false);
LL a,b,c;
while(cin>> a >> b)
{
LL ans;
ans=fastPow(a,b);
cout << ans << endl;
}
return 0;
}
2、快速幂取模
利用上面的性质( a * b ) % m = ( ( a % m ) * ( b % m ) ) % m;
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
LL fastPow(LL a,LL n,LL c)
{
LL base=a;
LL res=1;
const LL mod=c;
while(n)
{
if(n&1)
res=(res*base)%mod;
base=(base*base)%mod;
n>>=1;
}
return res;
}
int main()
{
ios::sync_with_stdio(false);
LL a,b,c;
while(cin>> a >> b >> c)
{
LL ans;
ans=fastPow(a,b,c);
cout << ans << endl;
}
return 0;
}
三、ged&&lcm
1、gcd模板
typedef long long LL;
LL gcd(LL a,LL b)
{
return b?gcd(b,a%b):a;
}
上述的是运用了gcd(a,b)=gcd(b,a%b)的性质;
c++中封装了gcd,可以直接调用:__gcd(a,b);
2、lcm
lcm(a,b)=a*b/gcd(a,b);
3、gcd与lcm的常用性质
- a,b可以分解成素数的因子;
- gcd(a,b)中只包含了所有a,b的全部公共素因子(取交集)(可以想象把a,b分解成因子,公共的必定能整除a,b);
- lcm(a,b)中包含了a,b所有的素因子(取并集);
- lcm*gcd=a*b;
- lcm/gcd=(a/gcd)*(b/gcd);
- gcd(k*a,k*b)=k*gcd(a,b);
- lcm(k*a,k*b)=k*lcm(a,b);
四、埃式素数筛
const int MAXN=1e7; //定义你所需要的空间大小
int prime[MAXN+1]; //存放素数
bool visit[MAXN+1]; //筛板
int E_sieve(int n) //埃式筛法
{
for(int i=0;i<=n;i++) //将筛板初始化
visit[i]=0;
for(int i=2;i*i<=n;i++) //遍历。此处是经过优化的i*i<=n比i<=sqrt(n)更快
{ //such as:非素数k一定能被sqrt(k)整除;
if(visit[i]==0) //开始筛i的倍数
{
for(int j=i*i;j<=n;j+=i)
visit[j]=1
}
}
int k=0; //统计素数的个数
for(int i=2;i<=n;i++) //存放素数放到prime中
{
if(visit[i]==0)
prime[++k]=i;
}
return k;
}