「算法」费马小定理 欧拉函数 裴蜀定理 曹冲养猪

中国剩余定理

  • 费马小定理
  • 欧拉函数
  • 裴蜀定理
  • 曹冲养猪
    • 题目描述
    • 输入格式
    • 输出格式
    • 分析

费马小定理

 费马小定理 ( F e r m a t ′ s l i t t l e t h e o r e m ) (Fermat's little theorem) (Fermatslittletheorem)是数论中的一个重要定理,在1636年提出。如果p是一个质数,而整数a不是p的倍数,则有 a a a ^ \hat{} ^ ( p − 1 ) ≡ 1 ( m o d (p-1)≡1(mod (p1)1(mod p ) p) p)
   5 3 ≡ 1 ( m o d 5^3≡1(mod 531(mod 2 ) 2) 2)
   2 6 ≡ 1 ( m o d 2^6≡1(mod 261(mod 7 ) 7) 7)

欧拉函数

 在数论,对正整数n,欧拉函数是小于或等于n的正整数中与n互质的数的数目
 此函数以其首名研究者欧拉命名 ( E u l e r ′ s t o t i e n t f u n c t i o n ) (Euler's totient function) (Eulerstotientfunction),它又称为 E u l e r ′ s t o t i e n t f u n c t i o n Euler's totient function Eulerstotientfunction φ φ φ函数、欧拉商数等
 然后就有 a a a φ ( n ) φ(n) φ(n) ≡ 1 ( m o d ≡1(mod 1(mod p ) p) p)

裴蜀定理

 对于任意整数 a a a b b b,存在一对整数 x x x y y y,满足 a x + b y = g c d ( a , b ) ax+by=gcd(a,b) ax+by=gcd(ab)

int exgcd(int a, int b, int &x, int &y) {
	if (b == 0) {
		x = 1;
		y = 0;
		return a;
	}
	int d = exgcd(b, a % b, x, y);
	int z = x;
	x = y;
	y = z - y * (a / b);
	return d;
}

曹冲养猪

题目描述

自从曹冲搞定了大象以后,曹操就开始琢磨让儿子干些事业,于是派他到中原养猪场养猪,可是曹冲很不高兴,于是在工作中马马虎虎,有一次曹操想知道母猪的数量,于是曹冲想狠狠耍曹操一把。

举个例子,假如有 16 头母猪,如果建了 3 个猪圈,剩下 1 头猪就没有地方安家了;如果建造了 5 个猪圈,但是仍然有 1 头猪没有地方去;如果建造了 7 个猪圈,还有 2 头没有地方去。你作为曹总的私人秘书理所当然要将准确的猪数报给曹总,你该怎么办?

输入格式

第一行包含一个整数 n ,表示建立猪圈的次数;

接下来 n 行,每行两个整数 a_i, b_i ,表示建立了 a_i 个猪圈,有 b_i 头猪没有去处。你可以假定 a_i,a_j 互质。

输出格式

输出仅包含一个正整数,即为曹冲至少养猪的数目。

输入
3
3 1
5 1
7 2
输出
16

分析

这道题有一种朴素算法

  1. 样例1
    输入
    2 3 1 5 2
    % 3 = 1 : 1 、 4 \%3=1:1、4 %3=1:14 7 7 7 10... 10... 10...
    % 5 = 2 : 2 \%5=2:2 %5=2:2 7 7 7 12... 12... 12...
    输出
    7 7 7

  2. 样例2
    输入
    3 3 1 5 2 7 3
    % 3 = 1 : 1 、 4 \%3=1:1、4 %3=1:14 7 7 7 10... 10... 10...
    % 5 = 2 : 2 \%5=2:2 %5=2:2 7 7 7 12... 12... 12...

    % 3 = 1 且 % 5 = 2 : 7 、 22 、 37 \%3=1 且 \%5=2:7、22、37 %3=1%5=2:72237 52 52 52 67... 67... 67...
    % 7 = 3 : 3 、 10 、 17 、 24 、 31 、 38 、 45 \%7=3:3、10、17、24、31、38、45 %7=3:3101724313845 52 52 52 59... 59... 59...
    输出
    52 52 52

#include 
#include 
#include 
using namespace std;

const int M = 1e3 + 5;
int a, b, x, y;
int n;

queue <int > m1;	//用两个队列来枚举
queue <int > m2;

void Calculation() {
	m1.push(b), m2.push(y);
	while (m1.back() != m2.back()) {
		int p = m1.back(), q = m2.back();
		if (p > q) {
			m2.push((p - q + x - 1) / x * x + q);
		}
		if (p < q) {
			m1.push((q - p + a - 1) / a * a + p);
		}
	}
	b = m1.back(), a = a * x;
}

int main() {
	scanf("%d", &n);
	scanf("%d %d", &a, &b);
	for(int i = 1; i < n; i ++) {
		scanf("%d %d", &x, &y);
		Calculation();
	}
	printf("%d", b);
	return 0;
}

很不幸的是,我TLE了


中国剩余定理

#include 
#include 
using namespace std;

const int M = 15;
long long a[M], b[M];
long long x, y, m, k;
long long ans, mod = 1;
int n;

long long exgcd(long long a, long long b, long long &x, long long &y) {
	if (b == 0) {
		x = 1;
		y = 0;
		return a;
	}
	int d = exgcd(b, a % b, x, y);
	int z = x;
	x = y;
	y = z - y * (a / b);
	return d;
}

int main() {
	scanf("%d", &n);
	for (int i = 1; i <= n; i ++) {
		scanf("%d %d", &a[i], &b[i]);
		mod *= a[i];
	}
	for (int i = 1; i <= n; i ++) {
		m = mod / a[i];
		exgcd(m, a[i], x, y);
		k = (a[i] + x % a[i]) % a[i];
		ans = (ans + b[i] * k * m) % mod;
	}
	printf("%lld", ans);
	return 0;
}

你可能感兴趣的:(算法,算法,c++)