算法学习过程——欧拉(费马小定理、欧拉函数、欧拉定理、欧拉降幂、欧拉筛法)_2

引言

        本篇主要讲解欧拉降幂,欧拉筛法。

        费马小定理、欧拉函数、欧拉定理在上篇博客已经讲解:算法学习过程——欧拉(费马小定理、欧拉函数、欧拉定理、欧拉降幂、欧拉筛法)_1

正文

欧拉降幂

        欧拉降幂主要应用的是欧拉函数以及欧拉定理的内容,不了解的可以先看引言中链接部分。

先抛出问题:

思路讲解        

扩展欧拉定理得:当 gcd(a,p) = 1,a^{b}mod p = a^{bmod\varphi p} modp

所以指数部分可以随意的对 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;//已经不是最小质因数,退出
		}
	}
}

 总结

        筛法的应用除了筛选素数外还有更多的拓展,此处不做过多讲解

        自用复习以及分享给大家,有任何问题可以留言或私信。

  • 16
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值