引言
本篇主要讲解欧拉降幂,欧拉筛法。
费马小定理、欧拉函数、欧拉定理在上篇博客已经讲解:算法学习过程——欧拉(费马小定理、欧拉函数、欧拉定理、欧拉降幂、欧拉筛法)_1
正文
欧拉降幂
欧拉降幂主要应用的是欧拉函数以及欧拉定理的内容,不了解的可以先看引言中链接部分。
先抛出问题:
思路讲解
扩展欧拉定理得:当 gcd(a,p) = 1,
所以指数部分可以随意的对 p 取模以实现降幂,但是由于指数部分输入非常大,所以应用秦九韶算法进行对指数的读入(奉上链接:秦九韶算法)先用字符串读入,再用取模函数进行操作的出最后的指数部分,再使用快速幂算法进行计算。
代码实现
#include "bits/stdc++.h"
using namespace std;
const int MOD = 998244353;
const int N = 209;
#define int long long
int a, b, ans, p;
string sb;
int qmi(int a,int b,int p)//快速幂
{
int res = 1;
while(b)
{
if(b & 1)res = res * a % p;
a = a * a % p;
b >>= 1;
}
return res;
}
int phi(int x)//求欧拉函数的值
{
int res = x;
int m = sqrt(x);
for(int i = 2;i <= m;++i)
{
if(x % i)continue;
res = res / i *(i-1);
while(x % i == 0)x /= i;
}
if(x > 1)res = res / x * (x-1);
return res;
}
int qmod(string s,int p)//秦九韶算法
{
int ans = 0;
for(auto &i : s)
{
ans = (ans * 10 + i - '0') % p;
}
return ans;
}
void solve(){
cin >> a >> sb >> p;//读入操作
b = 0;
int ph = phi(p);//求欧拉函数
ans = qmi(a,qmod(sb,ph),p);
cout << ans << '\n';
}
signed main() {
ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(0);
int _ = 1;
//cin >> _;
while(_--)solve();
return 0;
}
欧拉筛法
欧拉筛法,也叫线性筛法,可以筛选出小于等于 n 的素数有哪些。时间复杂度为 O(n)。
埃氏筛法
思路
埃氏筛法的思路比较简单:枚举每个数判断是不是素数,如果是素数,那 i 的倍数都不是素数。需要注意的是如果是素数就设为false,不是素数设为true。
代码实现
bool is_prime[N];
void Eratosthenes(int n)
{
is_prime[0] = is_prime[1] = true;
for (int i = 2; i <= n; ++i) is_prime[i] = false;
for (int i = 2; i <= n; ++i)
{
if (!is_prime[i])
{
for (int j = 2 * i; j <= n; j += i)
is_prime[j] = true; // 是 i 的倍数的均不是素数
}
}
}
如果不理解,想是素数设为 true ,不是素数设为 false 也可以。只不过最后判断遍历的时候要看清自己的设法。
bool is_prime[N];
void Eratosthenes(int n)
{
is_prime[0] = is_prime[1] = false;
for (int i = 2; i <= n; ++i) is_prime[i] = true;
for (int i = 2; i <= n; ++i)
{
if (is_prime[i])
{
for (int j = 2 * i; j <= n; j += i)
is_prime[j] = false; // 是 i 的倍数的均不是素数
}
}
}
欧拉筛法
思路
为了优化时间复杂度,和埃氏筛法的区别为:所以每个数只由它的最小质因数筛掉,不再重复筛去。核心思想在于判断 i 值是否为最小质因数。
代码实现
bitset<N>vis;
void euler(int n)
{
vector<int> primes;//素数表
vis[0] = vis[1] = true;
for(int i = 2;i <= n; ++ i)
{
if(!vis[i])primes.push_back(i);//是素数就放入素数表
//枚举素数表
for(int j = 0;j < primes.size() && i * primes[j] <= n;++ j)
{
vis[i * primes[j]] = true;
if(i % primes[j] == 0)break;//已经不是最小质因数,退出
}
}
}
总结
筛法的应用除了筛选素数外还有更多的拓展,此处不做过多讲解
自用复习以及分享给大家,有任何问题可以留言或私信。