简单的欧几里德与扩展欧几里德

1).扩展欧几里德的起手题——NOIP2012.同余方程

其实就是模版。

void ex_gcd(LL a, LL b,LL &x, LL &y)
{
	if (!b){
		x = 1; y = 0;
		return;
	} else {
		ex_gcd(b, a % b, x, y);
		int t = x;
		x = y; y = t - a / b * y;
	}
}

2).欧几里德的应用——bzoj1385.Division expression

除法表达式有如下的形式: X1/X2/X3…/Xk,其中 Xi 是正整数且 Xi<=1000000000 (1 <= i <= k, k <=10000)。除法表达式应当按照从左到右的顺序求,例如表达式1/2/1/2 的值为 1/4. 但可以在表达式中加入括号来改变计算顺序,例如 (1/2)/(1/2) 的值为 1. 现给出一个除法表达式 E,求是告诉是否可以通过增加括号来使其为E’, E’ 为整数。

首先E’一定可以表示成 X / Y 的形式。那么我们考虑分子分母上分别有那些数:第一,X1 一定出现在分子上。第二,不论怎么加括号 X2一定出现在分母上。第三其余的都可以出现在分子上。总之一句话,只有 X2 一定出现在分母上 —— X1/[X2/(X3/.../Xk)] ①。也就是说如果 ① 式是个整数,那么 E’就可以是整数,否则不论怎么加括号都不可能使E’为整数,因为 X2 总在分母上且总不能被消去。那么我们用分别求出 gcd(X2, Xi), 然后X2/gcd(X2, Xi)。如果最后 X21,那么可以为整数,否则就说明X2 总有不能被消去的因子。

#include <cstdio>
 
using namespace std;
 
const int MAX_N = 10005;
 
int T, n, a[MAX_N];
 
void init()
{
    scanf("%d", &n);
    for (int i = 1; i <= n; i ++) 
        scanf("%d", &a[i]);
}
 
int gcd(int a, int b)
{
    return (b == 0) ? a : gcd(b, a % b);
}
 
bool judge()
{
    a[2] /= gcd(a[1], a[2]);
    for (int i = 3; i <= n; i ++) a[2] /= gcd(a[i], a[2]);
    if (a[2] == 1) return 1;
    return 0;
}
 
void doit()
{
    if (judge()) printf("YES\n");
    else printf("NO\n");
}
 
int main()
{
    scanf("%d", &T);
    while (T --){
        init();
        doit();
    }
    return 0;
}

3).更多的扩展欧几里德

1.bzoj1477 && poj1061.青蛙的约会

有两只青蛙分别在一个长度为 L的环的 X 处和 Y 处,第一只每次可以跳 M 个单位距离,而第二只可以跳 N 个,问最少跳几次后能相遇,如果不能输出 "Impossible"

设跳了 t 次,X 青蛙跳的距离可以表示为:X + MtY 青蛙跳的距离可以是:Y + Nt,而如果他们相遇,那么他们的距离的差一定是 L 的倍数,因为是个环。所以我们可以得到式子:X + Mt - Y - Nt = k * L,所以 (M - N) * t - k * L = Y - X。利用扩展欧几里德求解。

#include <cstdio>

using namespace std;

typedef long long LL;

long long N, M, x, y, L;

void init()
{
	scanf("%lld%lld%lld%lld%lld", &x, &y, &M, &N, &L);
}

LL gcd(LL a, LL b)
{
	if (!b) return a;
	return gcd(b, a % b);
}

void ex_gcd(LL a, LL b, LL &X, LL &Y)
{
	if (!b){ X = 1, Y = 0; return; }
	else {
		ex_gcd(b, a % b, X, Y);
		LL t = X;
		X = Y; Y = t - a / b * X;
	}
}

void doit(void)
{
	LL a = M - N, b = L, c = y - x;
	LL g = gcd(a, b);
	if (c % g) { printf("Impossible\n"); return; }
	
	LL X, Y;
	ex_gcd(a, b, X, Y);
	X = X * c / g;
	X = (X % b + b) % b;
	if (!X) X = b;
	printf("%d\n", X);
	return;
}

int main(void)
{
	init(); doit();
	return 0;
}

2.poj2115.C Looooops

for (int i = a; i <= b; i += c, i %= 1 << k)能执行几次。死循环则输出 "FOREVER"

其实也就是求 (a + t * c) % (1 << k) = b % (1 << k),也就是t * c - l * (1 << k) = b - a。用扩欧求之。

#include <cstdio>

using namespace std;

typedef long long LL;

LL i, j, l, k;

LL gcd(LL a, LL b)
{
	return (b == 0) ? a : gcd(b, a % b);
}

void ex_gcd(LL a, LL b,LL &x, LL &y)
{
	if (!b){
		x = 1; y = 0;
		return;
	} else {
		ex_gcd(b, a % b, x, y);
		int t = x;
		x = y; y = t - a / b * y;
	}
}

void doit()
{
	LL a = l, c = j - i, b = 1;
	for (int p = 1; p <= k; p ++) b *= 2;  
	if (a < 0){
		a *= -1; b *= -1;
	}
	
	LL x, y, d = gcd(a, b);
	if (c % d != 0) { printf("FOREVER\n"); return; }
	
	a /= d; b /= d; c /= d;
	ex_gcd(a, b, x, y);
	x = (((x * c) % b) + b) % b;
	printf("%lld\n", x);
}

int main()
{
	while (scanf("%lld%lld%lld%lld", &i, &j, &l, &k) != EOF){
		if (i == 0 && j == 0 && l == 0 && k == 0) break;
		doit();
	}
	return 0;
}

3.bzoj1407.Savage(NOI2002)

一个岛上有若干洞穴排成一个环,有 N个野人,起初分别住在洞穴 Xi,每过一年,他们分别会向前走 Li (每个野人的Li 不同)并住下来,如果一个洞穴要住两个野人的时候,野人就会不高兴,从而使得小岛不安宁。但是令人惊奇的是,小岛从来没有过不安宁的情况,现在请你算出至少要多少个洞穴,才能使小岛永远和平。

很容易想到的算法是枚举 M,然后再用扩欧判断是否合法。但是 M10^6,算算复杂度感觉非常不靠谱。。大约 200000000,每个点0.5s 怎么跑得过?!但是网上的大神们好像都写得这种做法,我有点不明白。希望各位有人能解答我的疑问。

#include <cstdio>
#include <algorithm>
 
using namespace std;
 
const int MAX_N = 120;
 
int n, c[MAX_N], p[MAX_N], l[MAX_N];
int x, y, d, cnt = 0;
 
void init()
{
    scanf("%d", &n);
    for (int i = 1; i <= n; i ++) {
        scanf("%d%d%d", &c[i], &p[i], &l[i]),
        c[i] --,
        cnt = max(c[i], cnt);
    }
}
 
void ex_gcd(int a, int b, int &d, int &x, int &y)
{
    if (!b){
        x = 1; y = 0; d = a;
        return;
    } else {
        ex_gcd(b, a % b, d, x, y);
        int t = x;
        x = y; y = t - a / b * x;
    }
}
 
bool check(int m)
{
    for (int i = 1; i <= n; i ++)
        for (int j = i + 1; j <= n; j ++){
            int a = p[i] - p[j], b = m, C = c[j] - c[i];
            if (a < 0){
                a *= -1; C *= -1;     
            }
            ex_gcd(a, b, d, x, y);
            if (C % d) continue;
            int t = b / d;
            x = x * C / d;
            while (x < 0) x = x + t;
            while (x >= t) x = x - t;
            if (x <= l[i] && x <= l[j]) return 0;
        }
    return 1;
}
 
void doit()
{
    for (int i = cnt + 1; i <= 1000000; i ++)
        if (check(i)){ printf("%d\n", i); break; }
    return;
}
 
int main()
{
    init();
    doit();
    return 0;
} 







深度学习是机器学习的一个子领域,它基于人工神经网络的研究,特别是利用多层次的神经网络来进行学习和模式识别。深度学习模型能够学习数据的高层次特征,这些特征对于图像和语音识别、自然语言处理、医学图像分析等应用至关重要。以下是深度学习的一些关键概念和组成部分: 1. **神经网络(Neural Networks)**:深度学习的基础是人工神经网络,它是由多个层组成的网络结构,包括输入层、隐藏层和输出层。每个层由多个神经元组成,神经元之间通过权重连接。 2. **前馈神经网络(Feedforward Neural Networks)**:这是最常见的神经网络类型,信息从输入层流向隐藏层,最终到达输出层。 3. **卷积神经网络(Convolutional Neural Networks, CNNs)**:这种网络特别适合处理具有网格结构的数据,如图像。它们使用卷积层来提取图像的特征。 4. **循环神经网络(Recurrent Neural Networks, RNNs)**:这种网络能够处理序列数据,如时间序列或自然语言,因为它们具有记忆功能,能够捕捉数据中的时间依赖性。 5. **长短期记忆网络(Long Short-Term Memory, LSTM)**:LSTM 是一种特殊的 RNN,它能够学习长期依赖关系,非常适合复杂的序列预测任务。 6. **生成对抗网络(Generative Adversarial Networks, GANs)**:由两个网络组成,一个生成器和一个判别器,它们相互竞争,生成器生成数据,判别器评估数据的真实性。 7. **深度学习框架**:如 TensorFlow、Keras、PyTorch 等,这些框架提供了构建、训练和部署深度学习模型的工具和库。 8. **激活函数(Activation Functions)**:如 ReLU、Sigmoid、Tanh 等,它们在神经网络中用于添加非线性,使得网络能够学习复杂的函数。 9. **损失函数(Loss Functions)**:用于评估模型的预测与真实值之间的差异,常见的损失函数包括均方误差(MSE)、交叉熵(Cross-Entropy)等。 10. **优化算法(Optimization Algorithms)**:如梯度下降(Gradient Descent)、随机梯度下降(SGD)、Adam 等,用于更新网络权重,以最小化损失函数。 11. **正则化(Regularization)**:技术如 Dropout、L1/L2 正则化等,用于防止模型过拟合。 12. **迁移学习(Transfer Learning)**:利用在一个任务上训练好的模型来提高另一个相关任务的性能。 深度学习在许多领域都取得了显著的成就,但它也面临着一些挑战,如对大量数据的依赖、模型的解释性差、计算资源消耗大等。研究人员正在不断探索新的方法来解决这些问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值